@javascriptcommon/react-native-carplay 2.3.11 → 2.4.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/android/build.gradle +110 -0
  2. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  3. package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  4. package/android/gradle.properties +20 -0
  5. package/android/gradlew +234 -0
  6. package/android/gradlew.bat +89 -0
  7. package/android/src/main/AndroidManifest.xml +30 -0
  8. package/android/src/main/AndroidManifestNew.xml +30 -0
  9. package/android/src/main/java/org/birkir/carplay/CarPlayModule.kt +321 -0
  10. package/android/src/main/java/org/birkir/carplay/CarPlayPackage.kt +18 -0
  11. package/android/src/main/java/org/birkir/carplay/CarPlayService.kt +35 -0
  12. package/android/src/main/java/org/birkir/carplay/CarPlaySession.kt +126 -0
  13. package/android/src/main/java/org/birkir/carplay/parser/Ext.kt +11 -0
  14. package/android/src/main/java/org/birkir/carplay/parser/Parser.kt +18 -0
  15. package/android/src/main/java/org/birkir/carplay/parser/RCTGridTemplate.kt +28 -0
  16. package/android/src/main/java/org/birkir/carplay/parser/RCTListTemplate.kt +64 -0
  17. package/android/src/main/java/org/birkir/carplay/parser/RCTMapTemplate.kt +128 -0
  18. package/android/src/main/java/org/birkir/carplay/parser/RCTMessageTemplate.kt +28 -0
  19. package/android/src/main/java/org/birkir/carplay/parser/RCTPaneTemplate.kt +24 -0
  20. package/android/src/main/java/org/birkir/carplay/parser/RCTSearchTemplate.kt +41 -0
  21. package/android/src/main/java/org/birkir/carplay/parser/RCTTabTemplate.kt +157 -0
  22. package/android/src/main/java/org/birkir/carplay/parser/RCTTemplate.kt +419 -0
  23. package/android/src/main/java/org/birkir/carplay/parser/TemplateParser.kt +35 -0
  24. package/android/src/main/java/org/birkir/carplay/screens/CarScreen.kt +76 -0
  25. package/android/src/main/java/org/birkir/carplay/screens/CarScreenContext.kt +10 -0
  26. package/android/src/main/java/org/birkir/carplay/utils/EventEmitter.kt +167 -0
  27. package/android/src/main/java/org/birkir/carplay/utils/VirtualRenderer.kt +75 -0
  28. package/ios/RCTConvert+RNCarPlay.h +7 -8
  29. package/ios/RCTConvert+RNCarPlay.m +3 -2
  30. package/ios/RNCarPlay.h +11 -14
  31. package/ios/RNCarPlay.m +749 -945
  32. package/ios/RNCarPlayViewController.h +10 -0
  33. package/ios/RNCarPlayViewController.m +50 -0
  34. package/lib/CarPlay.d.ts +183 -0
  35. package/lib/CarPlay.d.ts.map +1 -0
  36. package/lib/index.d.ts +44 -0
  37. package/lib/index.d.ts.map +1 -0
  38. package/lib/interfaces/Action.d.ts +13 -0
  39. package/lib/interfaces/Action.d.ts.map +1 -0
  40. package/lib/interfaces/AlertAction.d.ts +6 -0
  41. package/lib/interfaces/AlertAction.d.ts.map +1 -0
  42. package/lib/interfaces/BarButton.d.ts +39 -0
  43. package/lib/interfaces/BarButton.d.ts.map +1 -0
  44. package/lib/interfaces/CarColor.d.ts +2 -0
  45. package/lib/interfaces/CarColor.d.ts.map +1 -0
  46. package/lib/interfaces/GridButton.d.ts +24 -0
  47. package/lib/interfaces/GridButton.d.ts.map +1 -0
  48. package/lib/interfaces/Header.d.ts +15 -0
  49. package/lib/interfaces/Header.d.ts.map +1 -0
  50. package/lib/interfaces/ListItem.d.ts +90 -0
  51. package/lib/interfaces/ListItem.d.ts.map +1 -0
  52. package/lib/interfaces/ListItemUpdate.d.ts +15 -0
  53. package/lib/interfaces/ListItemUpdate.d.ts.map +1 -0
  54. package/lib/interfaces/ListSection.d.ts +21 -0
  55. package/lib/interfaces/ListSection.d.ts.map +1 -0
  56. package/lib/interfaces/Maneuver.d.ts +31 -0
  57. package/lib/interfaces/Maneuver.d.ts.map +1 -0
  58. package/lib/interfaces/MapButton.d.ts +27 -0
  59. package/lib/interfaces/MapButton.d.ts.map +1 -0
  60. package/lib/interfaces/NavigationAlert.d.ts +44 -0
  61. package/lib/interfaces/NavigationAlert.d.ts.map +1 -0
  62. package/lib/interfaces/NavigationInfo.d.ts +17 -0
  63. package/lib/interfaces/NavigationInfo.d.ts.map +1 -0
  64. package/lib/interfaces/NavigationStep.d.ts +17 -0
  65. package/lib/interfaces/NavigationStep.d.ts.map +1 -0
  66. package/lib/interfaces/Pane.d.ts +29 -0
  67. package/lib/interfaces/Pane.d.ts.map +1 -0
  68. package/lib/interfaces/PauseReason.d.ts +8 -0
  69. package/lib/interfaces/PauseReason.d.ts.map +1 -0
  70. package/lib/interfaces/Place.d.ts +11 -0
  71. package/lib/interfaces/Place.d.ts.map +1 -0
  72. package/lib/interfaces/TextConfiguration.d.ts +6 -0
  73. package/lib/interfaces/TextConfiguration.d.ts.map +1 -0
  74. package/lib/interfaces/TimeRemainingColor.d.ts +2 -0
  75. package/lib/interfaces/TimeRemainingColor.d.ts.map +1 -0
  76. package/lib/interfaces/TravelEstimates.d.ts +37 -0
  77. package/lib/interfaces/TravelEstimates.d.ts.map +1 -0
  78. package/lib/interfaces/VoiceControlState.d.ts +8 -0
  79. package/lib/interfaces/VoiceControlState.d.ts.map +1 -0
  80. package/lib/navigation/NavigationSession.d.ts +18 -0
  81. package/lib/navigation/NavigationSession.d.ts.map +1 -0
  82. package/lib/navigation/Trip.d.ts +22 -0
  83. package/lib/navigation/Trip.d.ts.map +1 -0
  84. package/lib/templates/ActionSheetTemplate.d.ts +18 -0
  85. package/lib/templates/ActionSheetTemplate.d.ts.map +1 -0
  86. package/lib/templates/AlertTemplate.d.ts +17 -0
  87. package/lib/templates/AlertTemplate.d.ts.map +1 -0
  88. package/lib/templates/ContactTemplate.d.ts +36 -0
  89. package/lib/templates/ContactTemplate.d.ts.map +1 -0
  90. package/lib/templates/GridTemplate.d.ts +38 -0
  91. package/lib/templates/GridTemplate.d.ts.map +1 -0
  92. package/lib/templates/InformationTemplate.d.ts +28 -0
  93. package/lib/templates/InformationTemplate.d.ts.map +1 -0
  94. package/lib/templates/ListTemplate.d.ts +127 -0
  95. package/lib/templates/ListTemplate.d.ts.map +1 -0
  96. package/lib/templates/ListTemplate.js +24 -16
  97. package/lib/templates/MapTemplate.d.ts +171 -0
  98. package/lib/templates/MapTemplate.d.ts.map +1 -0
  99. package/lib/templates/NowPlayingTemplate.d.ts +31 -0
  100. package/lib/templates/NowPlayingTemplate.d.ts.map +1 -0
  101. package/lib/templates/PointOfInterestTemplate.d.ts +33 -0
  102. package/lib/templates/PointOfInterestTemplate.d.ts.map +1 -0
  103. package/lib/templates/SearchTemplate.d.ts +32 -0
  104. package/lib/templates/SearchTemplate.d.ts.map +1 -0
  105. package/lib/templates/SearchTemplate.js +2 -2
  106. package/lib/templates/TabBarTemplate.d.ts +27 -0
  107. package/lib/templates/TabBarTemplate.d.ts.map +1 -0
  108. package/lib/templates/Template.d.ts +82 -0
  109. package/lib/templates/Template.d.ts.map +1 -0
  110. package/lib/templates/VoiceControlTemplate.d.ts +18 -0
  111. package/lib/templates/VoiceControlTemplate.d.ts.map +1 -0
  112. package/lib/templates/android/AndroidNavigationBaseTemplate.d.ts +19 -0
  113. package/lib/templates/android/AndroidNavigationBaseTemplate.d.ts.map +1 -0
  114. package/lib/templates/android/MessageTemplate.d.ts +16 -0
  115. package/lib/templates/android/MessageTemplate.d.ts.map +1 -0
  116. package/lib/templates/android/NavigationTemplate.d.ts +44 -0
  117. package/lib/templates/android/NavigationTemplate.d.ts.map +1 -0
  118. package/lib/templates/android/PaneTemplate.d.ts +13 -0
  119. package/lib/templates/android/PaneTemplate.d.ts.map +1 -0
  120. package/lib/templates/android/PlaceListMapTemplate.d.ts +58 -0
  121. package/lib/templates/android/PlaceListMapTemplate.d.ts.map +1 -0
  122. package/lib/templates/android/PlaceListNavigationTemplate.d.ts +51 -0
  123. package/lib/templates/android/PlaceListNavigationTemplate.d.ts.map +1 -0
  124. package/lib/templates/android/RoutePreviewNavigationTemplate.d.ts +60 -0
  125. package/lib/templates/android/RoutePreviewNavigationTemplate.d.ts.map +1 -0
  126. package/package.json +3 -3
  127. package/react-native-carplay.podspec +3 -3
  128. package/src/CarPlay.ts +28 -16
  129. package/src/interfaces/ListItem.ts +14 -8
  130. package/src/interfaces/ListSection.ts +1 -1
  131. package/src/templates/ListTemplate.ts +64 -44
  132. package/src/templates/NowPlayingTemplate.ts +10 -3
  133. package/src/templates/SearchTemplate.ts +2 -2
  134. package/README.md +0 -633
@@ -0,0 +1,321 @@
1
+ package org.birkir.carplay
2
+
3
+ import android.content.Intent
4
+ import android.os.Handler
5
+ import android.os.Looper
6
+ import android.util.Log
7
+ import androidx.activity.OnBackPressedCallback
8
+ import androidx.car.app.AppManager
9
+ import androidx.car.app.CarContext
10
+ import androidx.car.app.CarToast
11
+ import androidx.car.app.ScreenManager
12
+ import androidx.car.app.SessionInfo
13
+ import androidx.car.app.model.Alert
14
+ import androidx.car.app.model.AlertCallback
15
+ import androidx.car.app.model.CarText
16
+ import androidx.car.app.model.Distance
17
+ import androidx.car.app.model.TabTemplate
18
+ import androidx.car.app.model.Template
19
+ import com.facebook.react.bridge.Arguments
20
+ import com.facebook.react.bridge.Callback
21
+ import com.facebook.react.bridge.LifecycleEventListener
22
+ import com.facebook.react.bridge.Promise
23
+ import com.facebook.react.bridge.ReactApplicationContext
24
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
25
+ import com.facebook.react.bridge.ReactMethod
26
+ import com.facebook.react.bridge.ReadableMap
27
+ import com.facebook.react.bridge.WritableNativeMap
28
+ import com.facebook.react.module.annotations.ReactModule
29
+ import com.facebook.react.modules.debug.DevSettingsModule
30
+ import org.birkir.carplay.parser.Parser
31
+ import org.birkir.carplay.parser.TemplateParser
32
+ import org.birkir.carplay.screens.CarScreen
33
+ import org.birkir.carplay.screens.CarScreenContext
34
+ import org.birkir.carplay.utils.EventEmitter
35
+ import java.util.WeakHashMap
36
+
37
+
38
+ @ReactModule(name = CarPlayModule.NAME)
39
+ class CarPlayModule internal constructor(private val reactContext: ReactApplicationContext) :
40
+ ReactContextBaseJavaModule(reactContext) {
41
+
42
+ private lateinit var carContext: CarContext
43
+ private lateinit var parser: Parser;
44
+
45
+ private var currentCarScreen: CarScreen? = null
46
+ private var screenManager: ScreenManager? = null
47
+ private val carScreens: WeakHashMap<String, CarScreen> = WeakHashMap()
48
+ private val carTemplates: WeakHashMap<String, ReadableMap> = WeakHashMap()
49
+ private val carScreenContexts: WeakHashMap<CarScreen, CarScreenContext> =
50
+ WeakHashMap()
51
+ private val handler: Handler = Handler(Looper.getMainLooper())
52
+
53
+
54
+ // Global event emitter (no templateId's)
55
+ private var eventEmitter: EventEmitter? = null
56
+
57
+ init {
58
+ reactContext.addLifecycleEventListener(object : LifecycleEventListener {
59
+ override fun onHostResume() {
60
+ eventEmitter = EventEmitter(reactContext)
61
+ reactContext.getNativeModule(DevSettingsModule::class.java)
62
+ ?.addMenuItem("Reload Android Auto")
63
+ }
64
+
65
+ override fun onHostPause() {}
66
+ override fun onHostDestroy() {}
67
+ })
68
+ }
69
+
70
+ override fun getName(): String {
71
+ return NAME
72
+ }
73
+
74
+ fun setCarContext(carContext: CarContext, currentCarScreen: CarScreen) {
75
+ parser = Parser(carContext, CarScreenContext("", eventEmitter!!, carScreens));
76
+ this.carContext = carContext
77
+ this.currentCarScreen = currentCarScreen
78
+ screenManager = currentCarScreen.screenManager
79
+ carScreens["root"] = this.currentCarScreen
80
+ carContext.onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
81
+ override fun handleOnBackPressed() {
82
+ eventEmitter?.backButtonPressed(screenManager?.top?.marker)
83
+ }
84
+ })
85
+ eventEmitter?.didConnect()
86
+ }
87
+
88
+ private fun parseTemplate(
89
+ config: ReadableMap,
90
+ carScreenContext: CarScreenContext
91
+ ): Template {
92
+ val factory = TemplateParser(carContext, carScreenContext)
93
+ return factory.parse(config)
94
+ }
95
+
96
+ @ReactMethod
97
+ fun checkForConnection() {
98
+ eventEmitter?.didConnect()
99
+ }
100
+
101
+ @ReactMethod
102
+ fun createTemplate(templateId: String, config: ReadableMap, callback: Callback?) {
103
+ handler.post {
104
+ Log.d(TAG, "Creating template $templateId")
105
+
106
+ // Store the template
107
+ carTemplates[templateId] = config;
108
+
109
+ try {
110
+ createScreen(templateId);
111
+ callback?.invoke()
112
+ } catch (err: IllegalArgumentException) {
113
+ val args = Arguments.createMap()
114
+ args.putString("error", "Failed to parse template '$templateId': ${err.message}")
115
+ callback?.invoke(args)
116
+ }
117
+ }
118
+ }
119
+
120
+ @ReactMethod
121
+ fun updateTemplate(templateId: String, config: ReadableMap) {
122
+ handler.post {
123
+ carTemplates[templateId] = config;
124
+ val screen = carScreens[templateId]
125
+ if (screen != null) {
126
+ val carScreenContext = carScreenContexts[screen];
127
+ if (carScreenContext != null) {
128
+ val template = parseTemplate(config, carScreenContext);
129
+ screen.setTemplate(template, templateId, config);
130
+ screen.invalidate()
131
+ // If this is a tab template, we need to update the main tab screen as well
132
+ if (template is TabTemplate) {
133
+ carScreens[carScreenContext.screenMarker]?.setTemplate(template, carScreenContext.screenMarker, config)
134
+ carScreens[carScreenContext.screenMarker]?.invalidate()
135
+ }
136
+ }
137
+ }
138
+ }
139
+ }
140
+
141
+ @ReactMethod
142
+ fun setRootTemplate(templateId: String, animated: Boolean?) {
143
+ Log.d(TAG, "set Root Template for $templateId")
144
+ handler.post {
145
+ val screen = getScreen(templateId)
146
+ if (screen != null) {
147
+ currentCarScreen = screen
148
+ screenManager?.popToRoot()
149
+ screenManager?.push(screen)
150
+ }
151
+ }
152
+ }
153
+
154
+ @ReactMethod
155
+ fun pushTemplate(templateId: String, animated: Boolean?) {
156
+ handler.post {
157
+ val screen = getScreen(templateId)
158
+ if (screen != null) {
159
+ currentCarScreen = screen;
160
+ screenManager?.push(screen)
161
+ }
162
+ }
163
+ }
164
+
165
+ @ReactMethod
166
+ fun popToTemplate(templateId: String, animated: Boolean?) {
167
+ handler.post {
168
+ screenManager?.popTo(templateId);
169
+ }
170
+ }
171
+
172
+ @ReactMethod
173
+ fun popTemplate(animated: Boolean?) {
174
+ handler.post {
175
+ screenManager!!.pop()
176
+ removeScreen(currentCarScreen)
177
+ currentCarScreen = screenManager!!.top as CarScreen
178
+ currentCarScreen?.invalidate()
179
+ }
180
+ }
181
+
182
+ @ReactMethod
183
+ fun presentTemplate(templateId: String?, animated: Boolean?) {
184
+ // void
185
+ }
186
+
187
+ @ReactMethod
188
+ fun dismissTemplate(templateId: String?, animated: Boolean?) {
189
+ // void
190
+ }
191
+
192
+ // pragma: Android Auto only stuff
193
+
194
+ @ReactMethod
195
+ fun toast(text: String, duration: Int) {
196
+ if (!::carContext.isInitialized) {
197
+ Log.e(TAG, "carContext is not initialized. Cannot show toast.")
198
+ return
199
+ }
200
+ CarToast.makeText(carContext, text, duration).show()
201
+ }
202
+
203
+ @ReactMethod
204
+ fun alert(props: ReadableMap) {
205
+ handler.post {
206
+ val id = props.getInt("id");
207
+ val title = parser.parseCarText(props.getString("title")!!, props);
208
+ val duration = props.getInt("duration").toLong();
209
+ val alert = Alert.Builder(id, title, duration).apply {
210
+ setCallback(object : AlertCallback {
211
+ override fun onCancel(reason: Int) {
212
+ val reasonString = when (reason) {
213
+ AlertCallback.REASON_TIMEOUT -> "timeout"
214
+ AlertCallback.REASON_USER_ACTION -> "userAction"
215
+ AlertCallback.REASON_NOT_SUPPORTED -> "notSupported"
216
+ else -> "unknown"
217
+ }
218
+ eventEmitter?.alertActionPressed("cancel", reasonString);
219
+ }
220
+ override fun onDismiss() {
221
+ eventEmitter?.alertActionPressed("dismiss" );
222
+ }
223
+ })
224
+ props.getString("subtitle")?.let { setSubtitle(parser.parseCarText(it, props)) }
225
+ props.getMap("icon")?.let { setIcon(parser.parseCarIcon(it)) }
226
+ props.getArray("actions")?.let {
227
+ for (i in 0 until it.size()) {
228
+ addAction(parser.parseAction(it.getMap(i)));
229
+ }
230
+ }
231
+ }.build()
232
+ carContext.getCarService(AppManager::class.java).showAlert(alert)
233
+ }
234
+ }
235
+
236
+ @ReactMethod
237
+ fun dismissAlert(alertId: Int) {
238
+ carContext.getCarService(AppManager::class.java).dismissAlert(alertId)
239
+ }
240
+
241
+ @ReactMethod
242
+ fun invalidate(templateId: String) {
243
+ handler.post {
244
+ val screen = getScreen(templateId)
245
+ if (screen === screenManager!!.top) {
246
+ Log.d(TAG, "Invalidated screen $templateId")
247
+ screen.invalidate()
248
+ }
249
+ }
250
+ }
251
+
252
+ @ReactMethod
253
+ fun reload() {
254
+ val intent = Intent("org.birkir.carplay.APP_RELOAD")
255
+ reactContext.sendBroadcast(intent)
256
+ }
257
+
258
+ @ReactMethod
259
+ fun getHostInfo(promise: Promise) {
260
+ return promise.resolve(Arguments.createMap().apply {
261
+ carContext.hostInfo?.packageName?.let { putString("packageName", it) }
262
+ carContext.hostInfo?.uid?.let { putInt("uid", it) }
263
+ });
264
+ }
265
+
266
+ // Others
267
+
268
+ @ReactMethod
269
+ fun addListener(eventName: String) {
270
+ Log.d(TAG, "listener added $eventName")
271
+ }
272
+
273
+ @ReactMethod
274
+ fun removeListeners(count: Int) {
275
+ Log.d(TAG, "remove listeners $count")
276
+ }
277
+
278
+ private fun createCarScreenContext(screen: CarScreen): CarScreenContext {
279
+ val templateId = screen.marker!!
280
+ return CarScreenContext(templateId, EventEmitter(reactContext, templateId), carScreens)
281
+ }
282
+
283
+ private fun createScreen(templateId: String): CarScreen? {
284
+ if (!::carContext.isInitialized) {
285
+ Log.e(TAG, "carContext is not initialized.")
286
+ return null
287
+ }
288
+ val config = carTemplates[templateId];
289
+ if (config != null) {
290
+ val screen = CarScreen(carContext)
291
+ screen.marker = templateId;
292
+
293
+ // context
294
+ carScreenContexts.remove(screen)
295
+ val carScreenContext = createCarScreenContext(screen)
296
+ carScreenContexts[screen] = carScreenContext
297
+
298
+ val template = parseTemplate(config, carScreenContext);
299
+ screen.setTemplate(template, templateId, config)
300
+ carScreens[templateId] = screen;
301
+
302
+ return screen;
303
+ }
304
+ return null;
305
+ }
306
+
307
+ private fun getScreen(name: String): CarScreen? {
308
+ return carScreens[name] ?: createScreen(name);
309
+ }
310
+
311
+ private fun removeScreen(screen: CarScreen?) {
312
+ val params = WritableNativeMap()
313
+ params.putString("screen", screen!!.marker)
314
+ carScreens.values.remove(screen)
315
+ }
316
+
317
+ companion object {
318
+ const val NAME = "RNCarPlay"
319
+ const val TAG = "CarPlay"
320
+ }
321
+ }
@@ -0,0 +1,18 @@
1
+ package org.birkir.carplay
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+ class CarPlayPackage : ReactPackage {
9
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
10
+ val modules: MutableList<NativeModule> = ArrayList()
11
+ modules.add(CarPlayModule(reactContext))
12
+ return modules
13
+ }
14
+
15
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
16
+ return emptyList()
17
+ }
18
+ }
@@ -0,0 +1,35 @@
1
+ package org.birkir.carplay
2
+
3
+ import android.content.BroadcastReceiver
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.content.IntentFilter
7
+ import android.util.Log
8
+ import androidx.car.app.CarAppService
9
+ import androidx.car.app.Session
10
+ import androidx.car.app.SessionInfo
11
+ import androidx.car.app.validation.HostValidator
12
+ import com.facebook.react.ReactApplication
13
+ import com.facebook.react.ReactInstanceManager
14
+
15
+ class CarPlayService : CarAppService() {
16
+ private lateinit var reactInstanceManager: ReactInstanceManager
17
+ override fun onCreate() {
18
+ super.onCreate()
19
+ reactInstanceManager =
20
+ (application as ReactApplication).reactNativeHost.reactInstanceManager
21
+ }
22
+
23
+ override fun createHostValidator(): HostValidator {
24
+ return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR
25
+ }
26
+
27
+ override fun onCreateSession(sessionInfo: SessionInfo): Session {
28
+ Log.d(TAG, "onCreateSession: sessionId = ${sessionInfo.sessionId}, display = ${sessionInfo.displayType}")
29
+ return CarPlaySession(reactInstanceManager)
30
+ }
31
+
32
+ companion object {
33
+ var TAG = "CarPlayService"
34
+ }
35
+ }
@@ -0,0 +1,126 @@
1
+ package org.birkir.carplay
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.BroadcastReceiver
5
+ import android.content.Context
6
+ import android.content.Intent
7
+ import android.content.IntentFilter
8
+ import android.content.res.Configuration
9
+ import android.os.Build
10
+ import android.os.Bundle
11
+ import android.util.Log
12
+ import androidx.car.app.CarContext.SCREEN_SERVICE
13
+ import androidx.car.app.Screen
14
+ import androidx.car.app.ScreenManager
15
+ import androidx.car.app.Session
16
+ import androidx.lifecycle.DefaultLifecycleObserver
17
+ import androidx.lifecycle.LifecycleOwner
18
+ import com.facebook.react.ReactInstanceManager
19
+ import com.facebook.react.bridge.Arguments
20
+ import com.facebook.react.bridge.ReactContext
21
+ import com.facebook.react.bridge.WritableNativeMap
22
+ import com.facebook.react.modules.appregistry.AppRegistry
23
+ import com.facebook.react.modules.core.TimingModule
24
+ import com.facebook.react.modules.debug.DevSettingsModule
25
+ import org.birkir.carplay.screens.CarScreen
26
+
27
+
28
+ class CarPlaySession(private val reactInstanceManager: ReactInstanceManager) : Session(), DefaultLifecycleObserver {
29
+ private lateinit var screen: CarScreen
30
+
31
+ @SuppressLint("UnspecifiedRegisterReceiverFlag")
32
+ override fun onCreateScreen(intent: Intent): Screen {
33
+ Log.d(TAG, "On create screen " + intent.action + " - " + intent.dataString)
34
+ val lifecycle = lifecycle
35
+ lifecycle.addObserver(this)
36
+ screen = CarScreen(carContext)
37
+ screen.marker = "root"
38
+
39
+ // Handle reload events
40
+ if (Build.VERSION.SDK_INT >= 34 && carContext.getApplicationInfo().targetSdkVersion >= 34) {
41
+ carContext.registerReceiver(object : BroadcastReceiver() {
42
+ override fun onReceive(context: Context, intent: Intent) {
43
+ if ("org.birkir.carplay.APP_RELOAD" == intent.action) {
44
+ invokeStartTask(reactInstanceManager.currentReactContext!!);
45
+ }
46
+ }
47
+ }, IntentFilter("org.birkir.carplay.APP_RELOAD"), Context.RECEIVER_EXPORTED)
48
+ }else{
49
+ carContext.registerReceiver(object : BroadcastReceiver() {
50
+ override fun onReceive(context: Context, intent: Intent) {
51
+ if ("org.birkir.carplay.APP_RELOAD" == intent.action) {
52
+ invokeStartTask(reactInstanceManager.currentReactContext!!);
53
+ }
54
+ }
55
+ }, IntentFilter("org.birkir.carplay.APP_RELOAD"))
56
+ }
57
+
58
+ // Run JS
59
+ runJsApplication()
60
+ return screen
61
+ }
62
+
63
+ private fun runJsApplication() {
64
+ val reactContext = reactInstanceManager.currentReactContext
65
+ if (reactContext == null) {
66
+ reactInstanceManager.addReactInstanceEventListener(
67
+ object : ReactInstanceManager.ReactInstanceEventListener {
68
+ override fun onReactContextInitialized(reactContext: ReactContext) {
69
+ invokeStartTask(reactContext)
70
+ reactInstanceManager.removeReactInstanceEventListener(this)
71
+ }
72
+ })
73
+ reactInstanceManager.createReactContextInBackground()
74
+ } else {
75
+ invokeStartTask(reactContext)
76
+ }
77
+ }
78
+
79
+ private fun invokeStartTask(reactContext: ReactContext) {
80
+ try {
81
+ val catalystInstance = reactContext.catalystInstance
82
+ val jsAppModuleName = "AndroidAuto"
83
+ val appParams = WritableNativeMap()
84
+ appParams.putDouble("rootTag", 1.0)
85
+ val appProperties = Bundle.EMPTY
86
+ if (appProperties != null) {
87
+ appParams.putMap("initialProps", Arguments.fromBundle(appProperties))
88
+ }
89
+
90
+ catalystInstance.getJSModule(AppRegistry::class.java)
91
+ .runApplication(jsAppModuleName, appParams)
92
+
93
+ val timingModule = reactContext.getNativeModule(
94
+ TimingModule::class.java
95
+ )
96
+ val carModule = reactInstanceManager
97
+ .currentReactContext?.getNativeModule(CarPlayModule::class.java)
98
+ carModule!!.setCarContext(carContext, screen)
99
+ timingModule!!.onHostResume()
100
+
101
+ } catch (e: Exception) {
102
+ e.printStackTrace()
103
+ }
104
+ }
105
+
106
+ override fun onDestroy(owner: LifecycleOwner) {
107
+ Log.i(TAG, "onDestroy")
108
+ val context = carContext
109
+ // stop services here, if any
110
+ }
111
+
112
+ override fun onNewIntent(intent: Intent) {
113
+ // handle intents
114
+ Log.d(TAG, "CarPlaySession.onNewIntent")
115
+ }
116
+
117
+ override fun onCarConfigurationChanged(configuration: Configuration) {
118
+ // we should report this over the bridge
119
+ Log.d(TAG, "CarPlaySession.onCarConfigurationChanged")
120
+ }
121
+
122
+ companion object {
123
+ const val TAG = "CarPlaySession"
124
+ }
125
+ }
126
+
@@ -0,0 +1,11 @@
1
+ package org.birkir.carplay.parser
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ fun ReadableMap.isLoading(): Boolean {
6
+ return try {
7
+ getBoolean("loading")
8
+ } catch (e: Exception) {
9
+ return false
10
+ }
11
+ }
@@ -0,0 +1,18 @@
1
+ package org.birkir.carplay.parser
2
+
3
+ import androidx.car.app.CarContext
4
+ import androidx.car.app.model.Pane
5
+ import androidx.car.app.model.PaneTemplate
6
+ import androidx.car.app.model.Template
7
+ import com.facebook.react.bridge.ReadableMap
8
+ import org.birkir.carplay.screens.CarScreenContext
9
+
10
+ class Parser(
11
+ context: CarContext,
12
+ carScreenContext: CarScreenContext
13
+ ) : RCTTemplate(context, carScreenContext) {
14
+ override fun parse(props: ReadableMap): Template {
15
+ return PaneTemplate.Builder(Pane.Builder().build()).build()
16
+ }
17
+
18
+ }
@@ -0,0 +1,28 @@
1
+ package org.birkir.carplay.parser
2
+
3
+ import androidx.car.app.CarContext
4
+ import androidx.car.app.model.GridTemplate
5
+ import com.facebook.react.bridge.ReadableMap
6
+ import org.birkir.carplay.screens.CarScreenContext
7
+
8
+ class RCTGridTemplate(
9
+ context: CarContext,
10
+ carScreenContext: CarScreenContext
11
+ ) : RCTTemplate(context, carScreenContext) {
12
+
13
+ override fun parse(props: ReadableMap): GridTemplate {
14
+ return GridTemplate.Builder().apply {
15
+ setLoading(props.isLoading())
16
+ props.getString("title")?.let { setTitle(it) }
17
+ props.getMap("headerAction")?.let { setHeaderAction(parseAction(it)) }
18
+ props.getArray("actions")?.let { setActionStrip(parseActionStrip(it)) }
19
+ this.setSingleList(
20
+ parseItemList(props.getArray("buttons"), "grid")
21
+ )
22
+ }.build()
23
+ }
24
+
25
+ companion object {
26
+ const val TAG = "RCTGridTemplate"
27
+ }
28
+ }
@@ -0,0 +1,64 @@
1
+ package org.birkir.carplay.parser
2
+
3
+ import androidx.car.app.CarContext
4
+ import androidx.car.app.model.ListTemplate
5
+ import androidx.car.app.model.SectionedItemList
6
+ import com.facebook.react.bridge.ReadableMap
7
+ import org.birkir.carplay.screens.CarScreenContext
8
+
9
+ class RCTListTemplate(
10
+ context: CarContext,
11
+ screenContext: CarScreenContext
12
+ ) : RCTTemplate(context, screenContext) {
13
+
14
+ override fun parse(props: ReadableMap): ListTemplate {
15
+ return ListTemplate.Builder().apply {
16
+ props.getString("title")?.let { setTitle(it) }
17
+
18
+ // Actions
19
+ props.getArray("actions")?.let {
20
+ setActionStrip(
21
+ parseActionStrip(it)
22
+ )
23
+ }
24
+
25
+ // Header Action
26
+ props.getMap("headerAction")?.let {
27
+ setHeaderAction(
28
+ parseAction(it)
29
+ )
30
+ }
31
+
32
+ // Loading
33
+ setLoading(props.isLoading())
34
+
35
+ // Sections
36
+ props.getArray("sections")?.let {
37
+ for (i in 0 until it.size()) {
38
+ val section = it.getMap(i)
39
+ val header = section.getString("header")
40
+ addSectionedList(
41
+ SectionedItemList.create(
42
+ parseItemList(section.getArray("items")),
43
+ header ?: "Missing title"
44
+ )
45
+ )
46
+ }
47
+ }
48
+
49
+ // Single List
50
+ // @todo handle when sections and items are defined at once.
51
+ props.getArray("items")?.let {
52
+ setSingleList(
53
+ parseItemList(it)
54
+ )
55
+ }
56
+
57
+ }.build()
58
+ }
59
+
60
+
61
+ companion object {
62
+ const val TAG = "RCTListTemplate"
63
+ }
64
+ }