@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.
- package/README.md +119 -0
- package/android/.idea/compiler.xml +6 -0
- package/android/.idea/gradle.xml +17 -0
- package/android/.idea/jarRepositories.xml +25 -0
- package/android/.idea/misc.xml +10 -0
- package/android/.idea/vcs.xml +6 -0
- package/android/build.gradle +63 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/android/gradle.properties +20 -0
- package/android/gradlew +234 -0
- package/android/gradlew.bat +89 -0
- package/android/local.properties +8 -0
- package/android/src/main/AndroidManifest.xml +31 -0
- package/android/src/main/AndroidManifestNew.xml +31 -0
- package/android/src/main/java/org/birkir/carplay/CarPlayModule.kt +348 -0
- package/android/src/main/java/org/birkir/carplay/CarPlayPackage.kt +18 -0
- package/android/src/main/java/org/birkir/carplay/CarPlayService.kt +34 -0
- package/android/src/main/java/org/birkir/carplay/CarPlaySession.kt +114 -0
- package/android/src/main/java/org/birkir/carplay/parser/Ext.kt +11 -0
- package/android/src/main/java/org/birkir/carplay/parser/Parser.kt +18 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTGridTemplate.kt +28 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTListTemplate.kt +64 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTMapTemplate.kt +185 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTMessageTemplate.kt +36 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTPaneTemplate.kt +24 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTSearchTemplate.kt +41 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTTabTemplate.kt +52 -0
- package/android/src/main/java/org/birkir/carplay/parser/RCTTemplate.kt +434 -0
- package/android/src/main/java/org/birkir/carplay/parser/TemplateParser.kt +35 -0
- package/android/src/main/java/org/birkir/carplay/screens/CarScreen.kt +69 -0
- package/android/src/main/java/org/birkir/carplay/screens/CarScreenContext.kt +10 -0
- package/android/src/main/java/org/birkir/carplay/utils/EventEmitter.kt +174 -0
- package/android/src/main/java/org/birkir/carplay/utils/VirtualRenderer.kt +75 -0
- package/ios/RCTConvert+RNCarPlay.h +18 -0
- package/ios/RCTConvert+RNCarPlay.m +96 -0
- package/ios/RNCPStore.h +24 -0
- package/ios/RNCPStore.m +68 -0
- package/ios/RNCarPlay.h +29 -0
- package/ios/RNCarPlay.m +1839 -0
- package/ios/RNCarPlay.xcodeproj/project.pbxproj +300 -0
- package/lib/CarPlay.d.ts +196 -0
- package/lib/CarPlay.d.ts.map +1 -0
- package/lib/CarPlay.js +176 -0
- package/lib/CarPlay.js.map +1 -0
- package/lib/index.d.ts +44 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +64 -0
- package/lib/index.js.map +1 -0
- package/lib/interfaces/Action.d.ts +13 -0
- package/lib/interfaces/Action.d.ts.map +1 -0
- package/lib/interfaces/Action.js +3 -0
- package/lib/interfaces/Action.js.map +1 -0
- package/lib/interfaces/AlertAction.d.ts +6 -0
- package/lib/interfaces/AlertAction.d.ts.map +1 -0
- package/lib/interfaces/AlertAction.js +3 -0
- package/lib/interfaces/AlertAction.js.map +1 -0
- package/lib/interfaces/BarButton.d.ts +39 -0
- package/lib/interfaces/BarButton.d.ts.map +1 -0
- package/lib/interfaces/BarButton.js +3 -0
- package/lib/interfaces/BarButton.js.map +1 -0
- package/lib/interfaces/CarColor.d.ts +2 -0
- package/lib/interfaces/CarColor.d.ts.map +1 -0
- package/lib/interfaces/CarColor.js +3 -0
- package/lib/interfaces/CarColor.js.map +1 -0
- package/lib/interfaces/GridButton.d.ts +24 -0
- package/lib/interfaces/GridButton.d.ts.map +1 -0
- package/lib/interfaces/GridButton.js +3 -0
- package/lib/interfaces/GridButton.js.map +1 -0
- package/lib/interfaces/Header.d.ts +15 -0
- package/lib/interfaces/Header.d.ts.map +1 -0
- package/lib/interfaces/Header.js +3 -0
- package/lib/interfaces/Header.js.map +1 -0
- package/lib/interfaces/ListItem.d.ts +61 -0
- package/lib/interfaces/ListItem.d.ts.map +1 -0
- package/lib/interfaces/ListItem.js +3 -0
- package/lib/interfaces/ListItem.js.map +1 -0
- package/lib/interfaces/ListItemUpdate.d.ts +15 -0
- package/lib/interfaces/ListItemUpdate.d.ts.map +1 -0
- package/lib/interfaces/ListItemUpdate.js +3 -0
- package/lib/interfaces/ListItemUpdate.js.map +1 -0
- package/lib/interfaces/ListSection.d.ts +21 -0
- package/lib/interfaces/ListSection.d.ts.map +1 -0
- package/lib/interfaces/ListSection.js +3 -0
- package/lib/interfaces/ListSection.js.map +1 -0
- package/lib/interfaces/Maneuver.d.ts +31 -0
- package/lib/interfaces/Maneuver.d.ts.map +1 -0
- package/lib/interfaces/Maneuver.js +3 -0
- package/lib/interfaces/Maneuver.js.map +1 -0
- package/lib/interfaces/MapButton.d.ts +27 -0
- package/lib/interfaces/MapButton.d.ts.map +1 -0
- package/lib/interfaces/MapButton.js +3 -0
- package/lib/interfaces/MapButton.js.map +1 -0
- package/lib/interfaces/NavigationAlert.d.ts +44 -0
- package/lib/interfaces/NavigationAlert.d.ts.map +1 -0
- package/lib/interfaces/NavigationAlert.js +10 -0
- package/lib/interfaces/NavigationAlert.js.map +1 -0
- package/lib/interfaces/NavigationInfo.d.ts +17 -0
- package/lib/interfaces/NavigationInfo.d.ts.map +1 -0
- package/lib/interfaces/NavigationInfo.js +3 -0
- package/lib/interfaces/NavigationInfo.js.map +1 -0
- package/lib/interfaces/NavigationStep.d.ts +17 -0
- package/lib/interfaces/NavigationStep.d.ts.map +1 -0
- package/lib/interfaces/NavigationStep.js +3 -0
- package/lib/interfaces/NavigationStep.js.map +1 -0
- package/lib/interfaces/Pane.d.ts +29 -0
- package/lib/interfaces/Pane.d.ts.map +1 -0
- package/lib/interfaces/Pane.js +3 -0
- package/lib/interfaces/Pane.js.map +1 -0
- package/lib/interfaces/PauseReason.d.ts +8 -0
- package/lib/interfaces/PauseReason.d.ts.map +1 -0
- package/lib/interfaces/PauseReason.js +12 -0
- package/lib/interfaces/PauseReason.js.map +1 -0
- package/lib/interfaces/Place.d.ts +11 -0
- package/lib/interfaces/Place.d.ts.map +1 -0
- package/lib/interfaces/Place.js +3 -0
- package/lib/interfaces/Place.js.map +1 -0
- package/lib/interfaces/TextConfiguration.d.ts +6 -0
- package/lib/interfaces/TextConfiguration.d.ts.map +1 -0
- package/lib/interfaces/TextConfiguration.js +3 -0
- package/lib/interfaces/TextConfiguration.js.map +1 -0
- package/lib/interfaces/TimeRemainingColor.d.ts +2 -0
- package/lib/interfaces/TimeRemainingColor.d.ts.map +1 -0
- package/lib/interfaces/TimeRemainingColor.js +3 -0
- package/lib/interfaces/TimeRemainingColor.js.map +1 -0
- package/lib/interfaces/TravelEstimates.d.ts +37 -0
- package/lib/interfaces/TravelEstimates.d.ts.map +1 -0
- package/lib/interfaces/TravelEstimates.js +3 -0
- package/lib/interfaces/TravelEstimates.js.map +1 -0
- package/lib/interfaces/VoiceControlState.d.ts +8 -0
- package/lib/interfaces/VoiceControlState.d.ts.map +1 -0
- package/lib/interfaces/VoiceControlState.js +3 -0
- package/lib/interfaces/VoiceControlState.js.map +1 -0
- package/lib/navigation/NavigationSession.d.ts +18 -0
- package/lib/navigation/NavigationSession.d.ts.map +1 -0
- package/lib/navigation/NavigationSession.js +51 -0
- package/lib/navigation/NavigationSession.js.map +1 -0
- package/lib/navigation/Trip.d.ts +22 -0
- package/lib/navigation/Trip.d.ts.map +1 -0
- package/lib/navigation/Trip.js +18 -0
- package/lib/navigation/Trip.js.map +1 -0
- package/lib/templates/ActionSheetTemplate.d.ts +18 -0
- package/lib/templates/ActionSheetTemplate.d.ts.map +1 -0
- package/lib/templates/ActionSheetTemplate.js +16 -0
- package/lib/templates/ActionSheetTemplate.js.map +1 -0
- package/lib/templates/AlertTemplate.d.ts +17 -0
- package/lib/templates/AlertTemplate.d.ts.map +1 -0
- package/lib/templates/AlertTemplate.js +16 -0
- package/lib/templates/AlertTemplate.js.map +1 -0
- package/lib/templates/ContactTemplate.d.ts +36 -0
- package/lib/templates/ContactTemplate.d.ts.map +1 -0
- package/lib/templates/ContactTemplate.js +16 -0
- package/lib/templates/ContactTemplate.js.map +1 -0
- package/lib/templates/GridTemplate.d.ts +38 -0
- package/lib/templates/GridTemplate.d.ts.map +1 -0
- package/lib/templates/GridTemplate.js +17 -0
- package/lib/templates/GridTemplate.js.map +1 -0
- package/lib/templates/InformationTemplate.d.ts +28 -0
- package/lib/templates/InformationTemplate.d.ts.map +1 -0
- package/lib/templates/InformationTemplate.js +28 -0
- package/lib/templates/InformationTemplate.js.map +1 -0
- package/lib/templates/ListTemplate.d.ts +112 -0
- package/lib/templates/ListTemplate.d.ts.map +1 -0
- package/lib/templates/ListTemplate.js +57 -0
- package/lib/templates/ListTemplate.js.map +1 -0
- package/lib/templates/MapTemplate.d.ts +171 -0
- package/lib/templates/MapTemplate.d.ts.map +1 -0
- package/lib/templates/MapTemplate.js +115 -0
- package/lib/templates/MapTemplate.js.map +1 -0
- package/lib/templates/NowPlayingTemplate.d.ts +31 -0
- package/lib/templates/NowPlayingTemplate.d.ts.map +1 -0
- package/lib/templates/NowPlayingTemplate.js +18 -0
- package/lib/templates/NowPlayingTemplate.js.map +1 -0
- package/lib/templates/PointOfInterestTemplate.d.ts +38 -0
- package/lib/templates/PointOfInterestTemplate.d.ts.map +1 -0
- package/lib/templates/PointOfInterestTemplate.js +18 -0
- package/lib/templates/PointOfInterestTemplate.js.map +1 -0
- package/lib/templates/SearchTemplate.d.ts +32 -0
- package/lib/templates/SearchTemplate.d.ts.map +1 -0
- package/lib/templates/SearchTemplate.js +41 -0
- package/lib/templates/SearchTemplate.js.map +1 -0
- package/lib/templates/TabBarTemplate.d.ts +27 -0
- package/lib/templates/TabBarTemplate.d.ts.map +1 -0
- package/lib/templates/TabBarTemplate.js +26 -0
- package/lib/templates/TabBarTemplate.js.map +1 -0
- package/lib/templates/Template.d.ts +83 -0
- package/lib/templates/Template.d.ts.map +1 -0
- package/lib/templates/Template.js +71 -0
- package/lib/templates/Template.js.map +1 -0
- package/lib/templates/VoiceControlTemplate.d.ts +18 -0
- package/lib/templates/VoiceControlTemplate.d.ts.map +1 -0
- package/lib/templates/VoiceControlTemplate.js +20 -0
- package/lib/templates/VoiceControlTemplate.js.map +1 -0
- package/lib/templates/android/AndroidNavigationBaseTemplate.d.ts +19 -0
- package/lib/templates/android/AndroidNavigationBaseTemplate.d.ts.map +1 -0
- package/lib/templates/android/AndroidNavigationBaseTemplate.js +29 -0
- package/lib/templates/android/AndroidNavigationBaseTemplate.js.map +1 -0
- package/lib/templates/android/MessageTemplate.d.ts +16 -0
- package/lib/templates/android/MessageTemplate.d.ts.map +1 -0
- package/lib/templates/android/MessageTemplate.js +11 -0
- package/lib/templates/android/MessageTemplate.js.map +1 -0
- package/lib/templates/android/NavigationTemplate.d.ts +44 -0
- package/lib/templates/android/NavigationTemplate.d.ts.map +1 -0
- package/lib/templates/android/NavigationTemplate.js +17 -0
- package/lib/templates/android/NavigationTemplate.js.map +1 -0
- package/lib/templates/android/PaneTemplate.d.ts +20 -0
- package/lib/templates/android/PaneTemplate.d.ts.map +1 -0
- package/lib/templates/android/PaneTemplate.js +17 -0
- package/lib/templates/android/PaneTemplate.js.map +1 -0
- package/lib/templates/android/PlaceListMapTemplate.d.ts +78 -0
- package/lib/templates/android/PlaceListMapTemplate.d.ts.map +1 -0
- package/lib/templates/android/PlaceListMapTemplate.js +25 -0
- package/lib/templates/android/PlaceListMapTemplate.js.map +1 -0
- package/lib/templates/android/PlaceListNavigationTemplate.d.ts +51 -0
- package/lib/templates/android/PlaceListNavigationTemplate.d.ts.map +1 -0
- package/lib/templates/android/PlaceListNavigationTemplate.js +20 -0
- package/lib/templates/android/PlaceListNavigationTemplate.js.map +1 -0
- package/lib/templates/android/RoutePreviewNavigationTemplate.d.ts +60 -0
- package/lib/templates/android/RoutePreviewNavigationTemplate.d.ts.map +1 -0
- package/lib/templates/android/RoutePreviewNavigationTemplate.js +23 -0
- package/lib/templates/android/RoutePreviewNavigationTemplate.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +49 -0
- package/react-native-carplay.podspec +21 -0
- package/src/CarPlay.ts +320 -0
- package/src/index.ts +50 -0
- package/src/interfaces/Action.ts +15 -0
- package/src/interfaces/AlertAction.ts +5 -0
- package/src/interfaces/BarButton.ts +41 -0
- package/src/interfaces/CarColor.ts +1 -0
- package/src/interfaces/GridButton.ts +25 -0
- package/src/interfaces/Header.ts +16 -0
- package/src/interfaces/ListItem.ts +61 -0
- package/src/interfaces/ListItemUpdate.ts +14 -0
- package/src/interfaces/ListSection.ts +21 -0
- package/src/interfaces/Maneuver.ts +30 -0
- package/src/interfaces/MapButton.ts +27 -0
- package/src/interfaces/NavigationAlert.ts +46 -0
- package/src/interfaces/NavigationInfo.ts +19 -0
- package/src/interfaces/NavigationStep.ts +17 -0
- package/src/interfaces/Pane.ts +29 -0
- package/src/interfaces/PauseReason.ts +7 -0
- package/src/interfaces/Place.ts +12 -0
- package/src/interfaces/TextConfiguration.ts +5 -0
- package/src/interfaces/TimeRemainingColor.ts +1 -0
- package/src/interfaces/TravelEstimates.ts +39 -0
- package/src/interfaces/VoiceControlState.ts +8 -0
- package/src/navigation/NavigationSession.ts +57 -0
- package/src/navigation/Trip.ts +36 -0
- package/src/templates/ActionSheetTemplate.ts +21 -0
- package/src/templates/AlertTemplate.ts +20 -0
- package/src/templates/ContactTemplate.ts +45 -0
- package/src/templates/GridTemplate.ts +45 -0
- package/src/templates/InformationTemplate.ts +42 -0
- package/src/templates/ListTemplate.ts +150 -0
- package/src/templates/MapTemplate.ts +231 -0
- package/src/templates/NowPlayingTemplate.ts +38 -0
- package/src/templates/PointOfInterestTemplate.ts +42 -0
- package/src/templates/SearchTemplate.ts +70 -0
- package/src/templates/TabBarTemplate.ts +56 -0
- package/src/templates/Template.ts +165 -0
- package/src/templates/VoiceControlTemplate.ts +25 -0
- package/src/templates/android/AndroidNavigationBaseTemplate.ts +46 -0
- package/src/templates/android/MessageTemplate.ts +19 -0
- package/src/templates/android/NavigationTemplate.ts +50 -0
- package/src/templates/android/PaneTemplate.ts +26 -0
- package/src/templates/android/PlaceListMapTemplate.ts +94 -0
- package/src/templates/android/PlaceListNavigationTemplate.ts +57 -0
- 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
|
+
}
|