@santoshpk/react-native-carplay 1.0.3

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 (269) hide show
  1. package/README.md +119 -0
  2. package/android/.idea/compiler.xml +6 -0
  3. package/android/.idea/gradle.xml +17 -0
  4. package/android/.idea/jarRepositories.xml +25 -0
  5. package/android/.idea/misc.xml +10 -0
  6. package/android/.idea/vcs.xml +6 -0
  7. package/android/build.gradle +63 -0
  8. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  9. package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  10. package/android/gradle.properties +20 -0
  11. package/android/gradlew +234 -0
  12. package/android/gradlew.bat +89 -0
  13. package/android/local.properties +8 -0
  14. package/android/src/main/AndroidManifest.xml +31 -0
  15. package/android/src/main/AndroidManifestNew.xml +31 -0
  16. package/android/src/main/java/org/birkir/carplay/CarPlayModule.kt +348 -0
  17. package/android/src/main/java/org/birkir/carplay/CarPlayPackage.kt +18 -0
  18. package/android/src/main/java/org/birkir/carplay/CarPlayService.kt +34 -0
  19. package/android/src/main/java/org/birkir/carplay/CarPlaySession.kt +114 -0
  20. package/android/src/main/java/org/birkir/carplay/parser/Ext.kt +11 -0
  21. package/android/src/main/java/org/birkir/carplay/parser/Parser.kt +18 -0
  22. package/android/src/main/java/org/birkir/carplay/parser/RCTGridTemplate.kt +28 -0
  23. package/android/src/main/java/org/birkir/carplay/parser/RCTListTemplate.kt +64 -0
  24. package/android/src/main/java/org/birkir/carplay/parser/RCTMapTemplate.kt +185 -0
  25. package/android/src/main/java/org/birkir/carplay/parser/RCTMessageTemplate.kt +36 -0
  26. package/android/src/main/java/org/birkir/carplay/parser/RCTPaneTemplate.kt +24 -0
  27. package/android/src/main/java/org/birkir/carplay/parser/RCTSearchTemplate.kt +41 -0
  28. package/android/src/main/java/org/birkir/carplay/parser/RCTTabTemplate.kt +52 -0
  29. package/android/src/main/java/org/birkir/carplay/parser/RCTTemplate.kt +434 -0
  30. package/android/src/main/java/org/birkir/carplay/parser/TemplateParser.kt +35 -0
  31. package/android/src/main/java/org/birkir/carplay/screens/CarScreen.kt +69 -0
  32. package/android/src/main/java/org/birkir/carplay/screens/CarScreenContext.kt +10 -0
  33. package/android/src/main/java/org/birkir/carplay/utils/EventEmitter.kt +174 -0
  34. package/android/src/main/java/org/birkir/carplay/utils/VirtualRenderer.kt +75 -0
  35. package/ios/RCTConvert+RNCarPlay.h +18 -0
  36. package/ios/RCTConvert+RNCarPlay.m +96 -0
  37. package/ios/RNCPStore.h +24 -0
  38. package/ios/RNCPStore.m +68 -0
  39. package/ios/RNCarPlay.h +29 -0
  40. package/ios/RNCarPlay.m +1839 -0
  41. package/ios/RNCarPlay.xcodeproj/project.pbxproj +300 -0
  42. package/lib/CarPlay.d.ts +196 -0
  43. package/lib/CarPlay.d.ts.map +1 -0
  44. package/lib/CarPlay.js +176 -0
  45. package/lib/CarPlay.js.map +1 -0
  46. package/lib/index.d.ts +44 -0
  47. package/lib/index.d.ts.map +1 -0
  48. package/lib/index.js +64 -0
  49. package/lib/index.js.map +1 -0
  50. package/lib/interfaces/Action.d.ts +13 -0
  51. package/lib/interfaces/Action.d.ts.map +1 -0
  52. package/lib/interfaces/Action.js +3 -0
  53. package/lib/interfaces/Action.js.map +1 -0
  54. package/lib/interfaces/AlertAction.d.ts +6 -0
  55. package/lib/interfaces/AlertAction.d.ts.map +1 -0
  56. package/lib/interfaces/AlertAction.js +3 -0
  57. package/lib/interfaces/AlertAction.js.map +1 -0
  58. package/lib/interfaces/BarButton.d.ts +39 -0
  59. package/lib/interfaces/BarButton.d.ts.map +1 -0
  60. package/lib/interfaces/BarButton.js +3 -0
  61. package/lib/interfaces/BarButton.js.map +1 -0
  62. package/lib/interfaces/CarColor.d.ts +2 -0
  63. package/lib/interfaces/CarColor.d.ts.map +1 -0
  64. package/lib/interfaces/CarColor.js +3 -0
  65. package/lib/interfaces/CarColor.js.map +1 -0
  66. package/lib/interfaces/GridButton.d.ts +24 -0
  67. package/lib/interfaces/GridButton.d.ts.map +1 -0
  68. package/lib/interfaces/GridButton.js +3 -0
  69. package/lib/interfaces/GridButton.js.map +1 -0
  70. package/lib/interfaces/Header.d.ts +15 -0
  71. package/lib/interfaces/Header.d.ts.map +1 -0
  72. package/lib/interfaces/Header.js +3 -0
  73. package/lib/interfaces/Header.js.map +1 -0
  74. package/lib/interfaces/ListItem.d.ts +61 -0
  75. package/lib/interfaces/ListItem.d.ts.map +1 -0
  76. package/lib/interfaces/ListItem.js +3 -0
  77. package/lib/interfaces/ListItem.js.map +1 -0
  78. package/lib/interfaces/ListItemUpdate.d.ts +15 -0
  79. package/lib/interfaces/ListItemUpdate.d.ts.map +1 -0
  80. package/lib/interfaces/ListItemUpdate.js +3 -0
  81. package/lib/interfaces/ListItemUpdate.js.map +1 -0
  82. package/lib/interfaces/ListSection.d.ts +21 -0
  83. package/lib/interfaces/ListSection.d.ts.map +1 -0
  84. package/lib/interfaces/ListSection.js +3 -0
  85. package/lib/interfaces/ListSection.js.map +1 -0
  86. package/lib/interfaces/Maneuver.d.ts +31 -0
  87. package/lib/interfaces/Maneuver.d.ts.map +1 -0
  88. package/lib/interfaces/Maneuver.js +3 -0
  89. package/lib/interfaces/Maneuver.js.map +1 -0
  90. package/lib/interfaces/MapButton.d.ts +27 -0
  91. package/lib/interfaces/MapButton.d.ts.map +1 -0
  92. package/lib/interfaces/MapButton.js +3 -0
  93. package/lib/interfaces/MapButton.js.map +1 -0
  94. package/lib/interfaces/NavigationAlert.d.ts +44 -0
  95. package/lib/interfaces/NavigationAlert.d.ts.map +1 -0
  96. package/lib/interfaces/NavigationAlert.js +10 -0
  97. package/lib/interfaces/NavigationAlert.js.map +1 -0
  98. package/lib/interfaces/NavigationInfo.d.ts +17 -0
  99. package/lib/interfaces/NavigationInfo.d.ts.map +1 -0
  100. package/lib/interfaces/NavigationInfo.js +3 -0
  101. package/lib/interfaces/NavigationInfo.js.map +1 -0
  102. package/lib/interfaces/NavigationStep.d.ts +17 -0
  103. package/lib/interfaces/NavigationStep.d.ts.map +1 -0
  104. package/lib/interfaces/NavigationStep.js +3 -0
  105. package/lib/interfaces/NavigationStep.js.map +1 -0
  106. package/lib/interfaces/Pane.d.ts +29 -0
  107. package/lib/interfaces/Pane.d.ts.map +1 -0
  108. package/lib/interfaces/Pane.js +3 -0
  109. package/lib/interfaces/Pane.js.map +1 -0
  110. package/lib/interfaces/PauseReason.d.ts +8 -0
  111. package/lib/interfaces/PauseReason.d.ts.map +1 -0
  112. package/lib/interfaces/PauseReason.js +12 -0
  113. package/lib/interfaces/PauseReason.js.map +1 -0
  114. package/lib/interfaces/Place.d.ts +11 -0
  115. package/lib/interfaces/Place.d.ts.map +1 -0
  116. package/lib/interfaces/Place.js +3 -0
  117. package/lib/interfaces/Place.js.map +1 -0
  118. package/lib/interfaces/TextConfiguration.d.ts +6 -0
  119. package/lib/interfaces/TextConfiguration.d.ts.map +1 -0
  120. package/lib/interfaces/TextConfiguration.js +3 -0
  121. package/lib/interfaces/TextConfiguration.js.map +1 -0
  122. package/lib/interfaces/TimeRemainingColor.d.ts +2 -0
  123. package/lib/interfaces/TimeRemainingColor.d.ts.map +1 -0
  124. package/lib/interfaces/TimeRemainingColor.js +3 -0
  125. package/lib/interfaces/TimeRemainingColor.js.map +1 -0
  126. package/lib/interfaces/TravelEstimates.d.ts +37 -0
  127. package/lib/interfaces/TravelEstimates.d.ts.map +1 -0
  128. package/lib/interfaces/TravelEstimates.js +3 -0
  129. package/lib/interfaces/TravelEstimates.js.map +1 -0
  130. package/lib/interfaces/VoiceControlState.d.ts +8 -0
  131. package/lib/interfaces/VoiceControlState.d.ts.map +1 -0
  132. package/lib/interfaces/VoiceControlState.js +3 -0
  133. package/lib/interfaces/VoiceControlState.js.map +1 -0
  134. package/lib/navigation/NavigationSession.d.ts +18 -0
  135. package/lib/navigation/NavigationSession.d.ts.map +1 -0
  136. package/lib/navigation/NavigationSession.js +51 -0
  137. package/lib/navigation/NavigationSession.js.map +1 -0
  138. package/lib/navigation/Trip.d.ts +22 -0
  139. package/lib/navigation/Trip.d.ts.map +1 -0
  140. package/lib/navigation/Trip.js +18 -0
  141. package/lib/navigation/Trip.js.map +1 -0
  142. package/lib/templates/ActionSheetTemplate.d.ts +18 -0
  143. package/lib/templates/ActionSheetTemplate.d.ts.map +1 -0
  144. package/lib/templates/ActionSheetTemplate.js +16 -0
  145. package/lib/templates/ActionSheetTemplate.js.map +1 -0
  146. package/lib/templates/AlertTemplate.d.ts +17 -0
  147. package/lib/templates/AlertTemplate.d.ts.map +1 -0
  148. package/lib/templates/AlertTemplate.js +16 -0
  149. package/lib/templates/AlertTemplate.js.map +1 -0
  150. package/lib/templates/ContactTemplate.d.ts +36 -0
  151. package/lib/templates/ContactTemplate.d.ts.map +1 -0
  152. package/lib/templates/ContactTemplate.js +16 -0
  153. package/lib/templates/ContactTemplate.js.map +1 -0
  154. package/lib/templates/GridTemplate.d.ts +38 -0
  155. package/lib/templates/GridTemplate.d.ts.map +1 -0
  156. package/lib/templates/GridTemplate.js +17 -0
  157. package/lib/templates/GridTemplate.js.map +1 -0
  158. package/lib/templates/InformationTemplate.d.ts +28 -0
  159. package/lib/templates/InformationTemplate.d.ts.map +1 -0
  160. package/lib/templates/InformationTemplate.js +28 -0
  161. package/lib/templates/InformationTemplate.js.map +1 -0
  162. package/lib/templates/ListTemplate.d.ts +112 -0
  163. package/lib/templates/ListTemplate.d.ts.map +1 -0
  164. package/lib/templates/ListTemplate.js +57 -0
  165. package/lib/templates/ListTemplate.js.map +1 -0
  166. package/lib/templates/MapTemplate.d.ts +171 -0
  167. package/lib/templates/MapTemplate.d.ts.map +1 -0
  168. package/lib/templates/MapTemplate.js +115 -0
  169. package/lib/templates/MapTemplate.js.map +1 -0
  170. package/lib/templates/NowPlayingTemplate.d.ts +31 -0
  171. package/lib/templates/NowPlayingTemplate.d.ts.map +1 -0
  172. package/lib/templates/NowPlayingTemplate.js +18 -0
  173. package/lib/templates/NowPlayingTemplate.js.map +1 -0
  174. package/lib/templates/PointOfInterestTemplate.d.ts +38 -0
  175. package/lib/templates/PointOfInterestTemplate.d.ts.map +1 -0
  176. package/lib/templates/PointOfInterestTemplate.js +18 -0
  177. package/lib/templates/PointOfInterestTemplate.js.map +1 -0
  178. package/lib/templates/SearchTemplate.d.ts +32 -0
  179. package/lib/templates/SearchTemplate.d.ts.map +1 -0
  180. package/lib/templates/SearchTemplate.js +41 -0
  181. package/lib/templates/SearchTemplate.js.map +1 -0
  182. package/lib/templates/TabBarTemplate.d.ts +27 -0
  183. package/lib/templates/TabBarTemplate.d.ts.map +1 -0
  184. package/lib/templates/TabBarTemplate.js +26 -0
  185. package/lib/templates/TabBarTemplate.js.map +1 -0
  186. package/lib/templates/Template.d.ts +83 -0
  187. package/lib/templates/Template.d.ts.map +1 -0
  188. package/lib/templates/Template.js +71 -0
  189. package/lib/templates/Template.js.map +1 -0
  190. package/lib/templates/VoiceControlTemplate.d.ts +18 -0
  191. package/lib/templates/VoiceControlTemplate.d.ts.map +1 -0
  192. package/lib/templates/VoiceControlTemplate.js +20 -0
  193. package/lib/templates/VoiceControlTemplate.js.map +1 -0
  194. package/lib/templates/android/AndroidNavigationBaseTemplate.d.ts +19 -0
  195. package/lib/templates/android/AndroidNavigationBaseTemplate.d.ts.map +1 -0
  196. package/lib/templates/android/AndroidNavigationBaseTemplate.js +29 -0
  197. package/lib/templates/android/AndroidNavigationBaseTemplate.js.map +1 -0
  198. package/lib/templates/android/MessageTemplate.d.ts +16 -0
  199. package/lib/templates/android/MessageTemplate.d.ts.map +1 -0
  200. package/lib/templates/android/MessageTemplate.js +11 -0
  201. package/lib/templates/android/MessageTemplate.js.map +1 -0
  202. package/lib/templates/android/NavigationTemplate.d.ts +44 -0
  203. package/lib/templates/android/NavigationTemplate.d.ts.map +1 -0
  204. package/lib/templates/android/NavigationTemplate.js +17 -0
  205. package/lib/templates/android/NavigationTemplate.js.map +1 -0
  206. package/lib/templates/android/PaneTemplate.d.ts +20 -0
  207. package/lib/templates/android/PaneTemplate.d.ts.map +1 -0
  208. package/lib/templates/android/PaneTemplate.js +17 -0
  209. package/lib/templates/android/PaneTemplate.js.map +1 -0
  210. package/lib/templates/android/PlaceListMapTemplate.d.ts +78 -0
  211. package/lib/templates/android/PlaceListMapTemplate.d.ts.map +1 -0
  212. package/lib/templates/android/PlaceListMapTemplate.js +25 -0
  213. package/lib/templates/android/PlaceListMapTemplate.js.map +1 -0
  214. package/lib/templates/android/PlaceListNavigationTemplate.d.ts +51 -0
  215. package/lib/templates/android/PlaceListNavigationTemplate.d.ts.map +1 -0
  216. package/lib/templates/android/PlaceListNavigationTemplate.js +20 -0
  217. package/lib/templates/android/PlaceListNavigationTemplate.js.map +1 -0
  218. package/lib/templates/android/RoutePreviewNavigationTemplate.d.ts +60 -0
  219. package/lib/templates/android/RoutePreviewNavigationTemplate.d.ts.map +1 -0
  220. package/lib/templates/android/RoutePreviewNavigationTemplate.js +23 -0
  221. package/lib/templates/android/RoutePreviewNavigationTemplate.js.map +1 -0
  222. package/lib/tsconfig.tsbuildinfo +1 -0
  223. package/package.json +49 -0
  224. package/react-native-carplay.podspec +21 -0
  225. package/src/CarPlay.ts +320 -0
  226. package/src/index.ts +50 -0
  227. package/src/interfaces/Action.ts +15 -0
  228. package/src/interfaces/AlertAction.ts +5 -0
  229. package/src/interfaces/BarButton.ts +41 -0
  230. package/src/interfaces/CarColor.ts +1 -0
  231. package/src/interfaces/GridButton.ts +25 -0
  232. package/src/interfaces/Header.ts +16 -0
  233. package/src/interfaces/ListItem.ts +61 -0
  234. package/src/interfaces/ListItemUpdate.ts +14 -0
  235. package/src/interfaces/ListSection.ts +21 -0
  236. package/src/interfaces/Maneuver.ts +30 -0
  237. package/src/interfaces/MapButton.ts +27 -0
  238. package/src/interfaces/NavigationAlert.ts +46 -0
  239. package/src/interfaces/NavigationInfo.ts +19 -0
  240. package/src/interfaces/NavigationStep.ts +17 -0
  241. package/src/interfaces/Pane.ts +29 -0
  242. package/src/interfaces/PauseReason.ts +7 -0
  243. package/src/interfaces/Place.ts +12 -0
  244. package/src/interfaces/TextConfiguration.ts +5 -0
  245. package/src/interfaces/TimeRemainingColor.ts +1 -0
  246. package/src/interfaces/TravelEstimates.ts +39 -0
  247. package/src/interfaces/VoiceControlState.ts +8 -0
  248. package/src/navigation/NavigationSession.ts +57 -0
  249. package/src/navigation/Trip.ts +36 -0
  250. package/src/templates/ActionSheetTemplate.ts +21 -0
  251. package/src/templates/AlertTemplate.ts +20 -0
  252. package/src/templates/ContactTemplate.ts +45 -0
  253. package/src/templates/GridTemplate.ts +45 -0
  254. package/src/templates/InformationTemplate.ts +42 -0
  255. package/src/templates/ListTemplate.ts +150 -0
  256. package/src/templates/MapTemplate.ts +231 -0
  257. package/src/templates/NowPlayingTemplate.ts +38 -0
  258. package/src/templates/PointOfInterestTemplate.ts +42 -0
  259. package/src/templates/SearchTemplate.ts +70 -0
  260. package/src/templates/TabBarTemplate.ts +56 -0
  261. package/src/templates/Template.ts +165 -0
  262. package/src/templates/VoiceControlTemplate.ts +25 -0
  263. package/src/templates/android/AndroidNavigationBaseTemplate.ts +46 -0
  264. package/src/templates/android/MessageTemplate.ts +19 -0
  265. package/src/templates/android/NavigationTemplate.ts +50 -0
  266. package/src/templates/android/PaneTemplate.ts +26 -0
  267. package/src/templates/android/PlaceListMapTemplate.ts +94 -0
  268. package/src/templates/android/PlaceListNavigationTemplate.ts +57 -0
  269. package/src/templates/android/RoutePreviewNavigationTemplate.ts +66 -0
@@ -0,0 +1,434 @@
1
+ package org.birkir.carplay.parser
2
+
3
+ // import androidx.car.app.model.Template
4
+
5
+ import android.graphics.Bitmap
6
+ import android.text.Spannable
7
+ import android.text.SpannableString
8
+ import android.util.Log
9
+ import androidx.car.app.CarContext
10
+ import androidx.car.app.model.Action
11
+ import androidx.car.app.model.Action.FLAG_IS_PERSISTENT
12
+ import androidx.car.app.model.Action.FLAG_PRIMARY
13
+ import androidx.car.app.model.ActionStrip
14
+ import androidx.car.app.model.CarColor
15
+ import androidx.car.app.model.CarIcon
16
+ import androidx.car.app.model.CarLocation
17
+ import androidx.car.app.model.CarText
18
+ import androidx.car.app.model.DateTimeWithZone
19
+ import androidx.car.app.model.Distance
20
+ import androidx.car.app.model.DistanceSpan
21
+ import androidx.car.app.model.GridItem
22
+ import androidx.car.app.model.Header
23
+ import androidx.car.app.model.ItemList
24
+ import androidx.car.app.model.Metadata
25
+ import androidx.car.app.model.Pane
26
+ import androidx.car.app.model.Place
27
+ import androidx.car.app.model.PlaceMarker
28
+ import androidx.car.app.model.Row
29
+ import androidx.car.app.model.Template
30
+ import androidx.car.app.navigation.model.Lane
31
+ import androidx.car.app.navigation.model.LaneDirection
32
+ import androidx.car.app.navigation.model.Maneuver
33
+ import androidx.car.app.navigation.model.MessageInfo
34
+ import androidx.car.app.navigation.model.NavigationTemplate
35
+ import androidx.car.app.navigation.model.RoutingInfo
36
+ import androidx.car.app.navigation.model.Step
37
+ import androidx.car.app.navigation.model.TravelEstimate
38
+ import androidx.core.graphics.drawable.IconCompat
39
+ import com.facebook.common.references.CloseableReference
40
+ import com.facebook.datasource.DataSource
41
+ import com.facebook.datasource.DataSources
42
+ import com.facebook.drawee.backends.pipeline.Fresco
43
+ import com.facebook.imagepipeline.image.CloseableBitmap
44
+ import com.facebook.imagepipeline.image.CloseableImage
45
+ import com.facebook.imagepipeline.request.ImageRequestBuilder
46
+ import com.facebook.react.bridge.ReadableArray
47
+ import com.facebook.react.bridge.ReadableMap
48
+ import com.facebook.react.views.imagehelper.ImageSource
49
+ import org.birkir.carplay.screens.CarScreenContext
50
+ import org.birkir.carplay.utils.EventEmitter
51
+ import java.util.TimeZone
52
+
53
+
54
+ /**
55
+ * Base class for parsing the template based on the props passed from ReactNative
56
+ *
57
+ * @property context
58
+ * @property carScreenContext
59
+ */
60
+ abstract class RCTTemplate(
61
+ protected val context: CarContext,
62
+ protected val carScreenContext: CarScreenContext
63
+ ) {
64
+
65
+ abstract fun parse(props: ReadableMap): Template
66
+
67
+ protected val eventEmitter: EventEmitter
68
+ get() = carScreenContext.eventEmitter
69
+
70
+ fun parseCarIcon(map: ReadableMap): CarIcon {
71
+ val source = ImageSource(context, map.getString("uri"))
72
+ val imageRequest = ImageRequestBuilder.newBuilderWithSource(source.uri).build()
73
+ val dataSource = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, context)
74
+ val result = DataSources.waitForFinalResult(dataSource) as CloseableReference<CloseableBitmap>
75
+ val bitmap = result.get().underlyingBitmap
76
+
77
+ CloseableReference.closeSafely(result)
78
+ dataSource.close()
79
+
80
+ return CarIcon.Builder(IconCompat.createWithBitmap(bitmap)).build()
81
+ }
82
+
83
+ fun parseColor(colorName: String?): CarColor {
84
+ // @todo implement CarColor.createCustom(light: 0x00, dark: 0x00)
85
+ // maybe use react native tooling for this
86
+
87
+ return when (colorName) {
88
+ "blue" -> CarColor.BLUE
89
+ "green" -> CarColor.GREEN
90
+ "primary" -> CarColor.PRIMARY
91
+ "red" -> CarColor.RED
92
+ "secondary" -> CarColor.SECONDARY
93
+ "yellow" -> CarColor.YELLOW
94
+ "default" -> CarColor.DEFAULT
95
+ else -> CarColor.DEFAULT
96
+ }
97
+ }
98
+
99
+ fun parseAction(map: ReadableMap?): Action {
100
+ val type = map?.getString("type")
101
+ if (type == "appIcon") {
102
+ return Action.APP_ICON
103
+ } else if (type == "back") {
104
+ return Action.BACK
105
+ } else if (type == "pan") {
106
+ return Action.PAN
107
+ }
108
+ val id = map?.getString("id")
109
+ val builder = Action.Builder()
110
+ if (map != null) {
111
+ map.getString("title")?.let {
112
+ builder.setTitle(it)
113
+ }
114
+ map.getMap("icon")?.let {
115
+ builder.setIcon(parseCarIcon(it))
116
+ }
117
+ map.getString("visibility")?.let {
118
+ if (it == "primary") {
119
+ builder.setFlags(FLAG_PRIMARY)
120
+ }
121
+ if (it == "persistent") {
122
+ builder.setFlags(FLAG_IS_PERSISTENT)
123
+ }
124
+ }
125
+ try {
126
+ builder.setBackgroundColor(parseColor(map.getString("backgroundColor")))
127
+ } catch (e: Exception) {
128
+ e.printStackTrace()
129
+ }
130
+ builder.setOnClickListener {
131
+ if (id != null) {
132
+ eventEmitter.buttonPressed(id)
133
+ }
134
+ }
135
+ }
136
+ return builder.build()
137
+ }
138
+
139
+ protected fun parseActionStrip(actions: ReadableArray): ActionStrip {
140
+ val builder = ActionStrip.Builder()
141
+ for (i in 0 until actions.size()) {
142
+ val actionMap = actions.getMap(i)
143
+ val action = parseAction(actionMap)
144
+ builder.addAction(action)
145
+ }
146
+ return builder.build()
147
+ }
148
+
149
+ protected fun parseItemList(
150
+ items: ReadableArray?,
151
+ type: String = "row"
152
+ ): ItemList {
153
+ return ItemList.Builder().apply {
154
+ for (i in 0 until items!!.size()) {
155
+ if (type == "row") {
156
+ addItem(parseRowItem(items!!.getMap(i)!!, i))
157
+ } else if (type == "grid") {
158
+ addItem(parseGridItem(items!!.getMap(i)!!, i))
159
+ }
160
+ }
161
+ }.build()
162
+ }
163
+
164
+ protected fun parseRowItem(item: ReadableMap, index: Int): Row {
165
+ val id = item.getString("id") ?: index.toString()
166
+ return Row.Builder().apply {
167
+ item.getString("text")?.let { setTitle(it) }
168
+ item.getString("detailText")?.let { addText(it) }
169
+ item.getMap("image")?.let { setImage(parseCarIcon(it)) }
170
+ if (item.hasKey("browsable") && item.getBoolean("browsable")) {
171
+ setOnClickListener {
172
+ eventEmitter.didSelectListItem(
173
+ id,
174
+ index
175
+ )
176
+ }
177
+ }
178
+ }.build()
179
+ }
180
+
181
+ protected fun parseGridItem(item: ReadableMap, index: Int): GridItem {
182
+ val id = item.getString("id") ?: index.toString()
183
+ return GridItem.Builder().apply {
184
+ val titleVariants = item.getArray("titleVariants")
185
+ val metadata = item.getMap("metadata");
186
+
187
+ if (titleVariants != null) {
188
+ if (titleVariants.size() > 0) {
189
+ setTitle(parseCarText(
190
+ titleVariants!!.getString(0)!!,
191
+ metadata
192
+ ))
193
+ }
194
+ if (titleVariants.size() > 1) {
195
+ setText(titleVariants!!.getString(1)!!)
196
+ }
197
+ }
198
+ item.getMap("image")?.let { setImage(parseCarIcon(it)) }
199
+ setLoading(item.isLoading())
200
+ setOnClickListener {
201
+ eventEmitter.gridButtonPressed(id, index)
202
+ }
203
+ }.build()
204
+ }
205
+
206
+ fun parsePlace(props: ReadableMap): Place {
207
+ val builder = Place.Builder(
208
+ CarLocation.create(
209
+ props.getDouble("latitude"),
210
+ props.getDouble("longitude"),
211
+ )
212
+ )
213
+ PlaceMarker.Builder().apply {
214
+ if(props.hasKey("icon")){
215
+ setIcon(parseCarIcon(props.getMap("icon")!!), PlaceMarker.TYPE_IMAGE)
216
+ }
217
+ else if(props.hasKey("label")){
218
+ props.getString("label")?.let { setLabel(it) }
219
+ }
220
+ builder.setMarker(this.build())
221
+ }
222
+ return builder.build()
223
+ }
224
+
225
+ fun parseMetadata(props: ReadableMap?): Metadata? {
226
+ val type = props?.getString("type")
227
+ if (props == null || type == null || type != "place") {
228
+ Log.w(TAG, "parseMetaData: invalid type provided $type")
229
+ return null
230
+ }
231
+ return Metadata.Builder().setPlace(parsePlace(props)).build()
232
+ }
233
+
234
+ fun parseCarText(title: String, props: ReadableMap?): CarText {
235
+ val spanBuilder = SpannableString(title)
236
+ props?.let {
237
+ try {
238
+ val index = title.indexOf("%d")
239
+ if (index != -1) {
240
+ spanBuilder.setSpan(
241
+ DistanceSpan.create(parseDistance(props)),
242
+ index,
243
+ index + 2,
244
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE,
245
+ )
246
+ }
247
+ it
248
+ } catch (e: Exception) {
249
+ Log.w(TAG, "getCarText: failed to parse the CarText")
250
+ }
251
+ }
252
+ return CarText.Builder(spanBuilder).build()
253
+ }
254
+
255
+ protected fun buildRow(props: ReadableMap, index: Int): Row {
256
+ val id = props.getString("id") ?: index.toString()
257
+ val builder = Row.Builder()
258
+ builder.setTitle(
259
+ parseCarText(
260
+ props.getString("title")!!,
261
+ props.getMap("metadata")
262
+ )
263
+ )
264
+ props.getArray("texts")?.let {
265
+ for (i in 0 until it.size()) {
266
+ builder.addText(it!!.getString(i)!!)
267
+ }
268
+ }
269
+ props.getMap("image")?.let {
270
+ builder.setImage(parseCarIcon(it))
271
+ }
272
+ try {
273
+ // val onPress = props.getInt("onPress")
274
+ builder.setBrowsable(true)
275
+
276
+ builder.setOnClickListener {
277
+ eventEmitter.didSelectPointOfInterest(id, index)
278
+ }
279
+ } catch (e: Exception) {
280
+ Log.w(TAG, "buildRow: failed to set clickListener on the row")
281
+ }
282
+ parseMetadata(props.getMap("metadata"))?.let {
283
+ builder.setMetadata(it)
284
+ }
285
+ return builder.build()
286
+ }
287
+
288
+ protected fun parsePlaceItemList(items: ReadableArray?): ItemList {
289
+ return ItemList.Builder().apply {
290
+ for (i in 0 until items!!.size()) {
291
+
292
+ addItem(buildRow(items!!.getMap(i)!!,i))
293
+ }
294
+ }.build()
295
+ }
296
+ protected fun parseDistanceUnit(value: String?): Int {
297
+ return when (value) {
298
+ "meters" -> Distance.UNIT_METERS
299
+ "miles" -> Distance.UNIT_MILES
300
+ "kilometers" -> Distance.UNIT_KILOMETERS
301
+ "yards" -> Distance.UNIT_YARDS
302
+ "feet" -> Distance.UNIT_FEET
303
+ else -> Distance.UNIT_METERS
304
+ }
305
+ }
306
+
307
+ protected fun parseDistance(map: ReadableMap): Distance {
308
+ return Distance.create(map.getDouble("distance"), parseDistanceUnit(map.getString("distanceUnits")))
309
+ }
310
+
311
+ protected fun parsePane(item: ReadableMap): Pane {
312
+ return Pane.Builder().apply {
313
+ setLoading(item.isLoading())
314
+ item.getMap("image")?.let {
315
+ setImage(parseCarIcon(it))
316
+ }
317
+ item.getArray("actions")?.let {
318
+ for (i in 0 until it.size()) {
319
+ addAction(parseAction(it.getMap(i)))
320
+ }
321
+ }
322
+ item.getArray("items")?.let {
323
+ for (i in 0 until it.size()) {
324
+ addRow(parseRowItem(it!!.getMap(i)!!, i))
325
+ }
326
+ }
327
+ }.build()
328
+ }
329
+
330
+ protected fun parseHeader(map: ReadableMap): Header {
331
+ return Header.Builder().apply {
332
+ map.getString("title")?.let { setTitle(parseCarText(it, map)) }
333
+ map.getMap("startAction")?.let { setStartHeaderAction(parseAction(it)) }
334
+ map.getArray("endActions")?.let {
335
+ for (i in 0 until it.size()) {
336
+ addEndHeaderAction(parseAction(it.getMap(i)))
337
+ }
338
+ }
339
+ }.build()
340
+ }
341
+
342
+ protected fun parseStep(map: ReadableMap): Step {
343
+ return Step.Builder().apply {
344
+ map.getMap("lane")?.let { addLane(parseLane(it)) }
345
+ map.getString("cue")?.let { setCue(it) }
346
+ map.getMap("lanesImage")?.let { setLanesImage(parseCarIcon(it)) }
347
+ map.getMap("maneuver")?.let { setManeuver(parseManeuver(it)) }
348
+ map.getString("road")?.let { setRoad(it) }
349
+ }.build()
350
+ }
351
+
352
+ protected fun parseLane(map: ReadableMap): Lane {
353
+ val laneBuilder = Lane.Builder()
354
+ val shape = map.getInt("shape")
355
+ val recommended = map.getBoolean("recommended")
356
+ return laneBuilder.addDirection(LaneDirection.create(shape, recommended)).build()
357
+ }
358
+
359
+ protected fun parseManeuver(map: ReadableMap): Maneuver {
360
+ val type = map.getInt("type")
361
+ val builder = Maneuver.Builder(type)
362
+ builder.setIcon(parseCarIcon(map.getMap("icon")!!))
363
+ if (type == Maneuver.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE
364
+ || type == Maneuver.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE
365
+ ) {
366
+ builder.setRoundaboutExitAngle(map.getInt("roundaboutExitAngle"))
367
+ }
368
+
369
+ if (type == Maneuver.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW
370
+ || type == Maneuver.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW
371
+ || type == Maneuver.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE
372
+ || type == Maneuver.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE
373
+ ) {
374
+ builder.setRoundaboutExitNumber(map.getInt("roundaboutExitNumber"))
375
+ }
376
+
377
+ return builder.build()
378
+ }
379
+
380
+ protected fun parseMessageInfo(map: ReadableMap): MessageInfo {
381
+ val builder = MessageInfo.Builder(map.getString("title")!!)
382
+ map.getMap("icon")?.let { builder.setImage(parseCarIcon(it)) }
383
+ return builder.build()
384
+ }
385
+
386
+ protected fun parseTravelEstimate(map: ReadableMap): TravelEstimate {
387
+ val dateTimeMap = map.getMap("destinationTime")!!
388
+ val destinationDateTime = DateTimeWithZone.create(
389
+ dateTimeMap.getDouble("timeSinceEpochMillis").toLong(),
390
+ TimeZone.getTimeZone(dateTimeMap.getString("id")),
391
+ )
392
+ val builder = TravelEstimate.Builder(
393
+ Distance.create(
394
+ map.getDouble("distanceRemaining"),
395
+ parseDistanceUnit(map.getString("distanceUnits"))
396
+ ),
397
+ destinationDateTime,
398
+ )
399
+ map.getString("distanceRemainingColor")?.let {
400
+ builder.setRemainingDistanceColor(parseColor(it))
401
+ }
402
+ map.getString("timeRemainingColor")?.let {
403
+ builder.setRemainingTimeColor(parseColor(it))
404
+ }
405
+ builder.setRemainingTimeSeconds(map.getDouble("timeRemaining").toLong())
406
+ return builder.build()
407
+ }
408
+
409
+ protected fun parseRoutingInfo(map: ReadableMap): RoutingInfo {
410
+ return RoutingInfo.Builder()
411
+ .apply {
412
+ setLoading(map.isLoading())
413
+ setCurrentStep(
414
+ parseStep(map.getMap("step")!!),
415
+ parseDistance(map)
416
+ )
417
+ map.getMap("junctionImage")?.let { setJunctionImage(parseCarIcon(it)) }
418
+ map.getMap("nextStep")?.let { setNextStep(parseStep(it)) }
419
+ }.build()
420
+ }
421
+
422
+ protected fun parseNavigationInfo(map: ReadableMap): NavigationTemplate.NavigationInfo {
423
+ val type = map.getString("type")
424
+ return if (type == "routingInfo") {
425
+ parseRoutingInfo(map.getMap("info")!!)
426
+ } else {
427
+ parseMessageInfo(map.getMap("info")!!)
428
+ }
429
+ }
430
+
431
+ companion object {
432
+ const val TAG = "RNCarPlayTemplate"
433
+ }
434
+ }
@@ -0,0 +1,35 @@
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 TemplateParser internal constructor(
11
+ private val context: CarContext,
12
+ private val carScreenContext: CarScreenContext) {
13
+
14
+ fun parse(props: ReadableMap): Template {
15
+ val template = when (props.getString("type")) {
16
+ "list" -> RCTListTemplate(context, carScreenContext)
17
+ "grid" -> RCTGridTemplate(context, carScreenContext)
18
+ "map" -> RCTMapTemplate(context, carScreenContext)
19
+ "navigation" -> RCTMapTemplate(context, carScreenContext)
20
+ "place-list-map" -> RCTMapTemplate(context, carScreenContext)
21
+ "place-list-navigation" -> RCTMapTemplate(context, carScreenContext)
22
+ "route-preview" -> RCTMapTemplate(context, carScreenContext)
23
+ "pane" -> RCTPaneTemplate(context, carScreenContext)
24
+ "search" -> RCTSearchTemplate(context, carScreenContext)
25
+ "tabbar" -> RCTTabTemplate(context, carScreenContext)
26
+ "message" -> RCTMessageTemplate(context, carScreenContext)
27
+ else -> null
28
+ }
29
+
30
+ return template?.parse(props) ?: PaneTemplate
31
+ .Builder(
32
+ Pane.Builder().setLoading(true).build()
33
+ ).setTitle("Template missing").build()
34
+ }
35
+ }
@@ -0,0 +1,69 @@
1
+ package org.birkir.carplay.screens
2
+
3
+ import android.util.Log
4
+ import androidx.car.app.CarContext
5
+ import androidx.car.app.Screen
6
+ import androidx.car.app.model.Pane
7
+ import androidx.car.app.model.PaneTemplate
8
+ import androidx.car.app.model.PlaceListMapTemplate
9
+ import androidx.car.app.model.Template
10
+ import androidx.car.app.navigation.model.MapTemplate
11
+ import androidx.car.app.navigation.model.NavigationTemplate
12
+ import androidx.car.app.navigation.model.PlaceListNavigationTemplate
13
+ import androidx.car.app.navigation.model.RoutePreviewNavigationTemplate
14
+ import androidx.lifecycle.Lifecycle
15
+ import androidx.lifecycle.LifecycleEventObserver
16
+ import androidx.lifecycle.LifecycleOwner
17
+ import com.facebook.react.bridge.ReadableMap
18
+ import org.birkir.carplay.utils.VirtualRenderer
19
+
20
+ class CarScreen(carContext: CarContext) : Screen(carContext) {
21
+
22
+ var template: Template? = null
23
+ private var virtualRenderer: VirtualRenderer? = null
24
+
25
+ init {
26
+ lifecycle.addObserver(object : LifecycleEventObserver {
27
+ override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
28
+ if (event == Lifecycle.Event.ON_DESTROY && virtualRenderer != null) {
29
+ Log.d(TAG, "onStateChanged: got $event, removing virtual renderer")
30
+ virtualRenderer = null
31
+ }
32
+ }
33
+ })
34
+ }
35
+
36
+ fun setTemplate(template: Template?, templateId: String, props: ReadableMap) {
37
+ // allow MapTemplate, NavigationTemplate and PlaceListMapTemplate
38
+ val isSurfaceTemplate = template is MapTemplate
39
+ || template is NavigationTemplate
40
+ || template is PlaceListMapTemplate
41
+ || template is PlaceListNavigationTemplate
42
+ || template is RoutePreviewNavigationTemplate
43
+
44
+ if (isSurfaceTemplate && virtualRenderer == null) {
45
+ Log.d(TAG, "setTemplate: received navigation template with args: $templateId")
46
+ if (templateId == null) {
47
+ Log.w(
48
+ TAG,
49
+ "setTemplate: moduleName is null, please make sure you are setting id for map-template in ReactNative",
50
+ )
51
+ return
52
+ }
53
+ virtualRenderer = VirtualRenderer(carContext, templateId)
54
+ }
55
+ this.template = template
56
+ }
57
+
58
+ override fun onGetTemplate(): Template {
59
+ Log.d(TAG, "onGetTemplate for $marker")
60
+ return template ?: PaneTemplate.Builder(
61
+ Pane.Builder().setLoading(true).build()
62
+ ).setTitle("Please wait...").build()
63
+ // @todo allow set the loading title by translatable resource.
64
+ }
65
+
66
+ companion object {
67
+ const val TAG = "CarScreen"
68
+ }
69
+ }
@@ -0,0 +1,10 @@
1
+ package org.birkir.carplay.screens
2
+
3
+ import org.birkir.carplay.utils.EventEmitter
4
+ import java.util.WeakHashMap
5
+
6
+ data class CarScreenContext(
7
+ val screenMarker: String,
8
+ var eventEmitter: EventEmitter,
9
+ var screens: WeakHashMap<String, CarScreen>
10
+ )