@iternio/react-native-auto-play 0.3.7 → 0.3.8
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/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AndroidAutoService.kt +5 -16
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AndroidAutoSession.kt +21 -33
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlay.kt +7 -0
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridCluster.kt +6 -0
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/VirtualRenderer.kt +67 -64
- package/ios/hybrid/HybridAutoPlay.swift +7 -0
- package/ios/hybrid/HybridCluster.swift +22 -8
- package/lib/AutoPlayHeadlessJsTask.d.ts +2 -1
- package/lib/AutoPlayHeadlessJsTask.js +4 -5
- package/lib/components/SafeAreaInsetsContext.d.ts +1 -1
- package/lib/components/SafeAreaInsetsContext.js +1 -1
- package/lib/hooks/useAndroidAutoTelemetry.js +2 -1
- package/lib/hooks/useFocusedEffect.js +1 -1
- package/lib/hooks/useVoiceInput.d.ts +1 -1
- package/lib/hooks/useVoiceInput.js +1 -1
- package/lib/hybrid/HybridAndroidAutoTelemetry.android.d.ts +2 -0
- package/lib/hybrid/HybridAndroidAutoTelemetry.android.js +2 -0
- package/lib/hybrid/HybridAndroidAutoTelemetry.d.ts +2 -0
- package/lib/hybrid/HybridAndroidAutoTelemetry.js +1 -0
- package/lib/hybrid/HybridAutoPlay.d.ts +2 -0
- package/lib/hybrid/HybridAutoPlay.js +2 -0
- package/lib/index.d.ts +4 -4
- package/lib/index.js +5 -5
- package/lib/scenes/CarPlayDashboardScene.d.ts +3 -3
- package/lib/scenes/CarPlayDashboardScene.js +1 -1
- package/lib/templates/MapTemplate.d.ts +1 -1
- package/lib/templates/MapTemplate.js +1 -1
- package/lib/templates/MessageTemplate.d.ts +1 -1
- package/lib/templates/MessageTemplate.js +1 -1
- package/lib/templates/Template.js +1 -1
- package/package.json +6 -4
- package/src/AutoPlayHeadlessJsTask.ts +12 -9
- package/src/components/SafeAreaInsetsContext.tsx +2 -1
- package/src/hooks/useAndroidAutoTelemetry.ts +2 -1
- package/src/hooks/useFocusedEffect.ts +1 -1
- package/src/hooks/useVoiceInput.ts +2 -1
- package/src/hybrid/HybridAndroidAutoTelemetry.android.ts +5 -0
- package/src/hybrid/HybridAndroidAutoTelemetry.ts +3 -0
- package/src/hybrid/HybridAutoPlay.ts +4 -0
- package/src/index.ts +5 -9
- package/src/scenes/CarPlayDashboardScene.ts +1 -1
- package/src/templates/MapTemplate.ts +2 -1
- package/src/templates/MessageTemplate.ts +7 -7
- package/src/templates/Template.ts +1 -1
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/utils/ReactContextResolver.kt +0 -36
|
@@ -23,17 +23,11 @@ import androidx.core.app.NotificationCompat
|
|
|
23
23
|
import androidx.core.app.NotificationManagerCompat
|
|
24
24
|
import androidx.lifecycle.DefaultLifecycleObserver
|
|
25
25
|
import androidx.lifecycle.LifecycleOwner
|
|
26
|
-
import com.facebook.react.ReactApplication
|
|
27
26
|
import com.facebook.react.bridge.LifecycleEventListener
|
|
28
|
-
import com.
|
|
27
|
+
import com.margelo.nitro.NitroModules
|
|
29
28
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.AppInfo
|
|
30
|
-
import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.ReactContextResolver
|
|
31
|
-
import kotlinx.coroutines.CoroutineScope
|
|
32
|
-
import kotlinx.coroutines.Dispatchers
|
|
33
|
-
import kotlinx.coroutines.launch
|
|
34
29
|
|
|
35
30
|
class AndroidAutoService : CarAppService() {
|
|
36
|
-
private lateinit var reactContext: ReactContext
|
|
37
31
|
private lateinit var notificationManager: NotificationManager
|
|
38
32
|
|
|
39
33
|
private var isServiceBound = false
|
|
@@ -54,10 +48,7 @@ class AndroidAutoService : CarAppService() {
|
|
|
54
48
|
super.onCreate()
|
|
55
49
|
instance = this
|
|
56
50
|
|
|
57
|
-
|
|
58
|
-
reactContext = ReactContextResolver.getReactContext(application as ReactApplication)
|
|
59
|
-
reactContext.addLifecycleEventListener(reactLifecycleObserver)
|
|
60
|
-
}
|
|
51
|
+
NitroModules.applicationContext?.addLifecycleEventListener(reactLifecycleObserver)
|
|
61
52
|
|
|
62
53
|
notificationManager = getSystemService(NotificationManager::class.java)
|
|
63
54
|
val appLabel = AppInfo.getApplicationLabel(this)
|
|
@@ -72,7 +63,7 @@ class AndroidAutoService : CarAppService() {
|
|
|
72
63
|
}
|
|
73
64
|
|
|
74
65
|
override fun onCreateSession(sessionInfo: SessionInfo): Session {
|
|
75
|
-
val session = AndroidAutoSession(sessionInfo
|
|
66
|
+
val session = AndroidAutoSession(sessionInfo)
|
|
76
67
|
|
|
77
68
|
if (sessionInfo.displayType == SessionInfo.DISPLAY_TYPE_CLUSTER) {
|
|
78
69
|
return session
|
|
@@ -89,11 +80,9 @@ class AndroidAutoService : CarAppService() {
|
|
|
89
80
|
|
|
90
81
|
stopForeground(STOP_FOREGROUND_REMOVE)
|
|
91
82
|
|
|
92
|
-
|
|
93
|
-
return
|
|
94
|
-
}
|
|
83
|
+
NitroModules.applicationContext?.removeLifecycleEventListener(reactLifecycleObserver)
|
|
95
84
|
|
|
96
|
-
|
|
85
|
+
VirtualRenderer.remove()
|
|
97
86
|
}
|
|
98
87
|
|
|
99
88
|
private val reactLifecycleObserver = object : LifecycleEventListener {
|
|
@@ -12,21 +12,16 @@ import androidx.car.app.model.MessageTemplate
|
|
|
12
12
|
import androidx.car.app.model.Template
|
|
13
13
|
import androidx.lifecycle.DefaultLifecycleObserver
|
|
14
14
|
import androidx.lifecycle.LifecycleOwner
|
|
15
|
-
import com.facebook.react.ReactApplication
|
|
16
15
|
import com.facebook.react.bridge.LifecycleEventListener
|
|
17
|
-
import com.
|
|
16
|
+
import com.margelo.nitro.NitroModules
|
|
18
17
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.template.AndroidAutoTemplate
|
|
19
18
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.template.MapTemplate
|
|
20
19
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.AppInfo
|
|
21
|
-
import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.ReactContextResolver
|
|
22
|
-
import kotlinx.coroutines.CoroutineScope
|
|
23
|
-
import kotlinx.coroutines.Dispatchers
|
|
24
|
-
import kotlinx.coroutines.launch
|
|
25
20
|
import java.util.UUID
|
|
26
21
|
import java.util.concurrent.ConcurrentHashMap
|
|
27
22
|
import java.util.concurrent.CopyOnWriteArrayList
|
|
28
23
|
|
|
29
|
-
class AndroidAutoSession(sessionInfo: SessionInfo
|
|
24
|
+
class AndroidAutoSession(sessionInfo: SessionInfo) :
|
|
30
25
|
Session() {
|
|
31
26
|
|
|
32
27
|
private val isCluster = sessionInfo.displayType == SessionInfo.DISPLAY_TYPE_CLUSTER
|
|
@@ -89,34 +84,29 @@ class AndroidAutoSession(sessionInfo: SessionInfo, private val reactApplication:
|
|
|
89
84
|
}
|
|
90
85
|
|
|
91
86
|
lifecycle.addObserver(sessionLifecycleObserver)
|
|
87
|
+
NitroModules.applicationContext?.addLifecycleEventListener(reactLifecycleObserver)
|
|
92
88
|
|
|
93
|
-
|
|
94
|
-
reactContext = ReactContextResolver.getReactContext(reactApplication)
|
|
95
|
-
reactContext.addLifecycleEventListener(reactLifecycleObserver)
|
|
96
|
-
|
|
97
|
-
// TODO this is not required for templates that host a component, check if we need this for non-rendering templates
|
|
98
|
-
/*
|
|
99
|
-
val appRegistry = reactContext.getJSModule(AppRegistry::class.java)
|
|
100
|
-
?: throw ClassNotFoundException("could not get AppRegistry instance")
|
|
101
|
-
val jsAppModuleName = if (isCluster) "AndroidAutoCluster" else "AndroidAuto"
|
|
102
|
-
val appParams = WritableNativeMap().apply {
|
|
103
|
-
putMap("initialProps", Arguments.createMap().apply {
|
|
104
|
-
putString("id", clusterTemplateId)
|
|
105
|
-
})
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
appRegistry.runApplication(jsAppModuleName, appParams)
|
|
109
|
-
*/
|
|
110
|
-
|
|
111
|
-
if (clusterId != null) {
|
|
112
|
-
HybridCluster.emit(ClusterEventName.DIDCONNECTWITHWINDOW, clusterId)
|
|
113
|
-
return@launch
|
|
114
|
-
}
|
|
115
|
-
|
|
89
|
+
if (clusterId == null) {
|
|
116
90
|
HybridAutoPlay.emit(EventName.DIDCONNECT)
|
|
91
|
+
} else {
|
|
92
|
+
HybridCluster.emit(ClusterEventName.DIDCONNECTWITHWINDOW, clusterId)
|
|
117
93
|
}
|
|
118
94
|
|
|
119
95
|
return screen
|
|
96
|
+
|
|
97
|
+
// TODO this is not required for templates that host a component, check if we need this for non-rendering templates
|
|
98
|
+
/*
|
|
99
|
+
val appRegistry = reactContext.getJSModule(AppRegistry::class.java)
|
|
100
|
+
?: throw ClassNotFoundException("could not get AppRegistry instance")
|
|
101
|
+
val jsAppModuleName = if (isCluster) "AndroidAutoCluster" else "AndroidAuto"
|
|
102
|
+
val appParams = WritableNativeMap().apply {
|
|
103
|
+
putMap("initialProps", Arguments.createMap().apply {
|
|
104
|
+
putString("id", clusterTemplateId)
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
appRegistry.runApplication(jsAppModuleName, appParams)
|
|
109
|
+
*/
|
|
120
110
|
}
|
|
121
111
|
|
|
122
112
|
override fun onCarConfigurationChanged(configuration: Configuration) {
|
|
@@ -129,7 +119,7 @@ class AndroidAutoSession(sessionInfo: SessionInfo, private val reactApplication:
|
|
|
129
119
|
}
|
|
130
120
|
|
|
131
121
|
val marker = AndroidAutoScreen.getScreen(ROOT_SESSION)?.marker ?: return
|
|
132
|
-
val config = AndroidAutoTemplate.getConfig(marker) as MapTemplateConfig? ?: return
|
|
122
|
+
val config = AndroidAutoTemplate.getConfig(marker) as? MapTemplateConfig? ?: return
|
|
133
123
|
|
|
134
124
|
if (config.onAppearanceDidChange != null) {
|
|
135
125
|
config.onAppearanceDidChange(colorScheme)
|
|
@@ -218,7 +208,6 @@ class AndroidAutoSession(sessionInfo: SessionInfo, private val reactApplication:
|
|
|
218
208
|
|
|
219
209
|
override fun onDestroy(owner: LifecycleOwner) {
|
|
220
210
|
sessions.remove(moduleName)
|
|
221
|
-
VirtualRenderer.removeRenderer(moduleName)
|
|
222
211
|
clusterId?.let {
|
|
223
212
|
HybridCluster.emit(ClusterEventName.DIDDISCONNECT, clusterId)
|
|
224
213
|
clusterSessions.remove(it)
|
|
@@ -247,7 +236,6 @@ class AndroidAutoSession(sessionInfo: SessionInfo, private val reactApplication:
|
|
|
247
236
|
const val TAG = "AndroidAutoSession"
|
|
248
237
|
const val ROOT_SESSION = "AutoPlayRoot"
|
|
249
238
|
|
|
250
|
-
private lateinit var reactContext: ReactContext
|
|
251
239
|
private val sessions = ConcurrentHashMap<String, ScreenContext>()
|
|
252
240
|
|
|
253
241
|
private val clusterSessions = CopyOnWriteArrayList<String>()
|
package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlay.kt
CHANGED
|
@@ -9,6 +9,13 @@ import java.util.concurrent.ConcurrentHashMap
|
|
|
9
9
|
import java.util.concurrent.CopyOnWriteArrayList
|
|
10
10
|
|
|
11
11
|
class HybridAutoPlay : HybridAutoPlaySpec() {
|
|
12
|
+
init {
|
|
13
|
+
listeners.clear()
|
|
14
|
+
renderStateListeners.clear()
|
|
15
|
+
voiceInputListeners.clear()
|
|
16
|
+
safeAreaInsetsListeners.clear()
|
|
17
|
+
}
|
|
18
|
+
|
|
12
19
|
override fun addListener(
|
|
13
20
|
eventType: EventName, callback: () -> Unit
|
|
14
21
|
): () -> Unit {
|
package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridCluster.kt
CHANGED
|
@@ -6,6 +6,12 @@ import java.util.concurrent.ConcurrentHashMap
|
|
|
6
6
|
import java.util.concurrent.CopyOnWriteArrayList
|
|
7
7
|
|
|
8
8
|
class HybridCluster : HybridClusterSpec() {
|
|
9
|
+
init {
|
|
10
|
+
listeners.clear()
|
|
11
|
+
eventQueue.clear()
|
|
12
|
+
colorSchemeListeners.clear()
|
|
13
|
+
}
|
|
14
|
+
|
|
9
15
|
override fun addListener(
|
|
10
16
|
eventType: ClusterEventName, callback: (String) -> Unit
|
|
11
17
|
): () -> Unit {
|
package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/VirtualRenderer.kt
CHANGED
|
@@ -2,12 +2,11 @@ package com.margelo.nitro.swe.iternio.reactnativeautoplay
|
|
|
2
2
|
|
|
3
3
|
import android.app.Presentation
|
|
4
4
|
import android.content.Context
|
|
5
|
-
import android.view.ContextThemeWrapper
|
|
6
5
|
import android.graphics.Color
|
|
7
6
|
import android.graphics.Rect
|
|
8
7
|
import android.hardware.display.DisplayManager
|
|
8
|
+
import android.hardware.display.VirtualDisplay
|
|
9
9
|
import android.os.Bundle
|
|
10
|
-
import android.util.Log
|
|
11
10
|
import android.view.Display
|
|
12
11
|
import android.view.LayoutInflater
|
|
13
12
|
import android.view.View
|
|
@@ -15,11 +14,11 @@ import android.view.ViewGroup
|
|
|
15
14
|
import android.view.ViewTreeObserver
|
|
16
15
|
import android.widget.FrameLayout
|
|
17
16
|
import android.widget.TextView
|
|
17
|
+
import androidx.annotation.MainThread
|
|
18
18
|
import androidx.car.app.AppManager
|
|
19
19
|
import androidx.car.app.CarContext
|
|
20
20
|
import androidx.car.app.SurfaceCallback
|
|
21
21
|
import androidx.car.app.SurfaceContainer
|
|
22
|
-
import com.facebook.react.ReactApplication
|
|
23
22
|
import com.facebook.react.bridge.Arguments
|
|
24
23
|
import com.facebook.react.bridge.ReactContext
|
|
25
24
|
import com.facebook.react.fabric.FabricUIManager
|
|
@@ -28,13 +27,11 @@ import com.facebook.react.runtime.ReactSurfaceView
|
|
|
28
27
|
import com.facebook.react.uimanager.DisplayMetricsHolder
|
|
29
28
|
import com.facebook.react.uimanager.UIManagerHelper
|
|
30
29
|
import com.facebook.react.uimanager.common.UIManagerType
|
|
30
|
+
import com.margelo.nitro.NitroModules
|
|
31
31
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.template.AndroidAutoTemplate
|
|
32
32
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.AppInfo
|
|
33
33
|
import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.Debouncer
|
|
34
|
-
import
|
|
35
|
-
import kotlinx.coroutines.CoroutineScope
|
|
36
|
-
import kotlinx.coroutines.Dispatchers
|
|
37
|
-
import kotlinx.coroutines.launch
|
|
34
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
38
35
|
import kotlin.math.floor
|
|
39
36
|
|
|
40
37
|
class VirtualRenderer(
|
|
@@ -42,14 +39,7 @@ class VirtualRenderer(
|
|
|
42
39
|
private val moduleName: String,
|
|
43
40
|
private val isCluster: Boolean = false
|
|
44
41
|
) {
|
|
45
|
-
private
|
|
46
|
-
|
|
47
|
-
private fun isUiManagerInitialized(): Boolean {
|
|
48
|
-
return ::fabricUiManager.isInitialized
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
private lateinit var display: Display
|
|
52
|
-
private lateinit var reactContext: ReactContext
|
|
42
|
+
private var virtualDisplay: VirtualDisplay? = null
|
|
53
43
|
|
|
54
44
|
private lateinit var reactSurfaceImpl: ReactSurfaceImpl
|
|
55
45
|
private var reactSurfaceView: ReactSurfaceView? = null
|
|
@@ -66,20 +56,13 @@ class VirtualRenderer(
|
|
|
66
56
|
private val virtualScreenDensity = context.resources.displayMetrics.density
|
|
67
57
|
val scale = BuildConfig.SCALE_FACTOR * virtualScreenDensity
|
|
68
58
|
|
|
59
|
+
private fun isSurfaceReady(surfaceContainer: SurfaceContainer): Boolean {
|
|
60
|
+
return surfaceContainer.surface != null && surfaceContainer.dpi != 0 && surfaceContainer.height != 0 && surfaceContainer.width != 0
|
|
61
|
+
}
|
|
62
|
+
|
|
69
63
|
init {
|
|
70
64
|
virtualRenderer[moduleName] = this
|
|
71
65
|
|
|
72
|
-
CoroutineScope(Dispatchers.Main).launch {
|
|
73
|
-
reactContext =
|
|
74
|
-
ReactContextResolver.getReactContext(context.applicationContext as ReactApplication)
|
|
75
|
-
|
|
76
|
-
fabricUiManager = UIManagerHelper.getUIManager(
|
|
77
|
-
reactContext, UIManagerType.FABRIC
|
|
78
|
-
) as FabricUIManager
|
|
79
|
-
|
|
80
|
-
initRenderer()
|
|
81
|
-
}
|
|
82
|
-
|
|
83
66
|
context.getCarService(AppManager::class.java).setSurfaceCallback(object : SurfaceCallback {
|
|
84
67
|
val areaDebouncer = Debouncer(200)
|
|
85
68
|
|
|
@@ -90,13 +73,14 @@ class VirtualRenderer(
|
|
|
90
73
|
var visibleArea = Rect(0, 0, 0, 0)
|
|
91
74
|
|
|
92
75
|
override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) {
|
|
93
|
-
if (surfaceContainer
|
|
94
|
-
Log.w(TAG, "surface is null")
|
|
76
|
+
if (!isSurfaceReady(surfaceContainer)) {
|
|
95
77
|
return
|
|
96
78
|
}
|
|
97
79
|
|
|
80
|
+
virtualDisplay?.release() // in case this is called multiple times release the old instance
|
|
81
|
+
|
|
98
82
|
val manager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
|
|
99
|
-
|
|
83
|
+
virtualDisplay = manager.createVirtualDisplay(
|
|
100
84
|
moduleName,
|
|
101
85
|
surfaceContainer.width,
|
|
102
86
|
surfaceContainer.height,
|
|
@@ -105,11 +89,15 @@ class VirtualRenderer(
|
|
|
105
89
|
DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION,
|
|
106
90
|
)
|
|
107
91
|
|
|
108
|
-
display = virtualDisplay
|
|
92
|
+
val display = virtualDisplay?.display ?: return
|
|
109
93
|
height = surfaceContainer.height
|
|
110
94
|
width = surfaceContainer.width
|
|
111
95
|
|
|
112
|
-
initRenderer()
|
|
96
|
+
initRenderer(display)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
override fun onSurfaceDestroyed(surfaceContainer: SurfaceContainer) {
|
|
100
|
+
stop()
|
|
113
101
|
}
|
|
114
102
|
|
|
115
103
|
override fun onScroll(distanceX: Float, distanceY: Float) {
|
|
@@ -247,10 +235,12 @@ class VirtualRenderer(
|
|
|
247
235
|
return AndroidAutoTemplate.getTypedConfig<MapTemplateConfig>(marker)
|
|
248
236
|
}
|
|
249
237
|
|
|
250
|
-
private fun initRenderer() {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
238
|
+
private fun initRenderer(display: Display) {
|
|
239
|
+
val reactContext = NitroModules.applicationContext ?: return
|
|
240
|
+
|
|
241
|
+
val fabricUiManager = UIManagerHelper.getUIManager(
|
|
242
|
+
reactContext, UIManagerType.FABRIC
|
|
243
|
+
) as? FabricUIManager? ?: return
|
|
254
244
|
|
|
255
245
|
val initialProperties = Bundle().apply {
|
|
256
246
|
putString("id", moduleName)
|
|
@@ -270,20 +260,21 @@ class VirtualRenderer(
|
|
|
270
260
|
val mainScreenDensity = DisplayMetricsHolder.getScreenDisplayMetrics().density
|
|
271
261
|
val reactNativeScale = virtualScreenDensity / mainScreenDensity * BuildConfig.SCALE_FACTOR
|
|
272
262
|
|
|
273
|
-
if (!isUiManagerInitialized()) {
|
|
274
|
-
// this makes sure we have all required instances
|
|
275
|
-
// no matter if the app is launched on the phone or AA first
|
|
276
|
-
return
|
|
277
|
-
}
|
|
278
|
-
|
|
279
263
|
FabricMapPresentation(
|
|
280
|
-
|
|
264
|
+
reactContext,
|
|
265
|
+
display,
|
|
266
|
+
fabricUiManager,
|
|
267
|
+
height,
|
|
268
|
+
width,
|
|
269
|
+
initialProperties,
|
|
270
|
+
reactNativeScale
|
|
281
271
|
).show()
|
|
282
272
|
}
|
|
283
273
|
|
|
284
274
|
inner class FabricMapPresentation(
|
|
285
|
-
private val context:
|
|
275
|
+
private val context: ReactContext,
|
|
286
276
|
display: Display,
|
|
277
|
+
private val fabricUiManager: FabricUIManager,
|
|
287
278
|
private val height: Int,
|
|
288
279
|
private val width: Int,
|
|
289
280
|
private val initialProperties: Bundle,
|
|
@@ -292,11 +283,8 @@ class VirtualRenderer(
|
|
|
292
283
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
293
284
|
super.onCreate(savedInstanceState)
|
|
294
285
|
|
|
295
|
-
val appTheme = context.applicationContext.applicationInfo.theme
|
|
296
|
-
val themedContext = ContextThemeWrapper(context.applicationContext, appTheme)
|
|
297
|
-
|
|
298
286
|
if (!this@VirtualRenderer::reactSurfaceImpl.isInitialized) {
|
|
299
|
-
reactSurfaceImpl = ReactSurfaceImpl(
|
|
287
|
+
reactSurfaceImpl = ReactSurfaceImpl(context, moduleName, initialProperties)
|
|
300
288
|
}
|
|
301
289
|
|
|
302
290
|
var splashScreenView: View? = null
|
|
@@ -305,9 +293,9 @@ class VirtualRenderer(
|
|
|
305
293
|
(it.parent as ViewGroup).removeView(it)
|
|
306
294
|
} ?: run {
|
|
307
295
|
splashScreenView =
|
|
308
|
-
if (isCluster) getClusterSplashScreen(
|
|
296
|
+
if (isCluster) getClusterSplashScreen(context, height, width) else null
|
|
309
297
|
|
|
310
|
-
val surfaceView = ReactSurfaceView(
|
|
298
|
+
val surfaceView = ReactSurfaceView(context, reactSurfaceImpl).apply {
|
|
311
299
|
layoutParams = FrameLayout.LayoutParams(
|
|
312
300
|
(width / reactNativeScale).toInt(), (height / reactNativeScale).toInt()
|
|
313
301
|
)
|
|
@@ -335,7 +323,7 @@ class VirtualRenderer(
|
|
|
335
323
|
)
|
|
336
324
|
|
|
337
325
|
// remove ui-managers lifecycle listener to not stop rendering when app is not in foreground/phone screen is off
|
|
338
|
-
|
|
326
|
+
context.removeLifecycleEventListener(fabricUiManager)
|
|
339
327
|
// trigger ui-managers onHostResume to make sure the surface is rendered properly even when AA only is starting without the phone app
|
|
340
328
|
fabricUiManager.onHostResume()
|
|
341
329
|
|
|
@@ -343,7 +331,7 @@ class VirtualRenderer(
|
|
|
343
331
|
}
|
|
344
332
|
|
|
345
333
|
|
|
346
|
-
val rootContainer = FrameLayout(
|
|
334
|
+
val rootContainer = FrameLayout(context).apply {
|
|
347
335
|
layoutParams = FrameLayout.LayoutParams(
|
|
348
336
|
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT
|
|
349
337
|
)
|
|
@@ -365,8 +353,7 @@ class VirtualRenderer(
|
|
|
365
353
|
): View {
|
|
366
354
|
val root = FrameLayout(context).apply {
|
|
367
355
|
layoutParams = ViewGroup.LayoutParams(
|
|
368
|
-
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
369
|
-
ViewGroup.LayoutParams.MATCH_PARENT
|
|
356
|
+
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
|
|
370
357
|
)
|
|
371
358
|
}
|
|
372
359
|
|
|
@@ -407,25 +394,41 @@ class VirtualRenderer(
|
|
|
407
394
|
})
|
|
408
395
|
}
|
|
409
396
|
|
|
397
|
+
@MainThread
|
|
398
|
+
private fun stop() {
|
|
399
|
+
virtualDisplay?.release()
|
|
400
|
+
virtualDisplay = null
|
|
401
|
+
|
|
402
|
+
val uiManager = NitroModules.applicationContext?.let {
|
|
403
|
+
UIManagerHelper.getUIManager(
|
|
404
|
+
it, UIManagerType.FABRIC
|
|
405
|
+
) as? FabricUIManager?
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
reactSurfaceId?.let {
|
|
410
|
+
uiManager?.stopSurface(it)
|
|
411
|
+
}
|
|
412
|
+
} catch (_: AssertionError) {
|
|
413
|
+
// Fabric already invalidated
|
|
414
|
+
} finally {
|
|
415
|
+
reactSurfaceId = null
|
|
416
|
+
virtualRenderer.remove(moduleName)
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
410
420
|
companion object {
|
|
411
421
|
const val TAG = "VirtualRenderer"
|
|
412
422
|
|
|
413
|
-
private val virtualRenderer =
|
|
423
|
+
private val virtualRenderer = ConcurrentHashMap<String, VirtualRenderer>()
|
|
414
424
|
|
|
415
425
|
fun hasRenderer(moduleId: String): Boolean {
|
|
416
426
|
return virtualRenderer.contains(moduleId)
|
|
417
427
|
}
|
|
418
428
|
|
|
419
|
-
fun
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
if (renderer?.isUiManagerInitialized() == true) {
|
|
423
|
-
renderer.reactSurfaceId?.let {
|
|
424
|
-
renderer.fabricUiManager.stopSurface(it)
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
virtualRenderer.remove(moduleId)
|
|
429
|
+
fun remove() {
|
|
430
|
+
virtualRenderer.forEach { (_, renderer) -> renderer.stop() }
|
|
431
|
+
virtualRenderer.clear()
|
|
429
432
|
}
|
|
430
433
|
}
|
|
431
434
|
}
|
|
@@ -21,6 +21,13 @@ class HybridAutoPlay: HybridAutoPlaySpec {
|
|
|
21
21
|
private static var renderStateListeners = [String: [RenderStateListener]]()
|
|
22
22
|
private static var safeAreaInsetsListeners = [String: [SafeAreaListener]]()
|
|
23
23
|
|
|
24
|
+
override init() {
|
|
25
|
+
HybridAutoPlay.listeners.removeAll()
|
|
26
|
+
HybridAutoPlay.renderStateListeners.removeAll()
|
|
27
|
+
HybridAutoPlay.safeAreaInsetsListeners.removeAll()
|
|
28
|
+
super.init()
|
|
29
|
+
}
|
|
30
|
+
|
|
24
31
|
func addListener(eventType: EventName, callback: @escaping () -> Void)
|
|
25
32
|
throws -> () -> Void
|
|
26
33
|
{
|
|
@@ -31,6 +31,16 @@ class HybridCluster: HybridClusterSpec {
|
|
|
31
31
|
String: (_: String, _: Bool) -> Void
|
|
32
32
|
]()
|
|
33
33
|
|
|
34
|
+
override init() {
|
|
35
|
+
HybridCluster.listeners.removeAll()
|
|
36
|
+
HybridCluster.eventQueue.removeAll()
|
|
37
|
+
HybridCluster.colorSchemeListeners.removeAll()
|
|
38
|
+
HybridCluster.zoomListeners.removeAll()
|
|
39
|
+
HybridCluster.compassListeners.removeAll()
|
|
40
|
+
HybridCluster.speedLimitListeners.removeAll()
|
|
41
|
+
super.init()
|
|
42
|
+
}
|
|
43
|
+
|
|
34
44
|
func addListener(
|
|
35
45
|
eventType: ClusterEventName,
|
|
36
46
|
callback: @escaping (_ clusterId: String) -> Void
|
|
@@ -57,12 +67,14 @@ class HybridCluster: HybridClusterSpec {
|
|
|
57
67
|
return Promise.async {
|
|
58
68
|
if #available(iOS 15.4, *) {
|
|
59
69
|
try await MainActor.run {
|
|
60
|
-
guard
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
guard
|
|
71
|
+
let scene = SceneStore.getClusterScene(
|
|
72
|
+
clusterId: clusterId
|
|
73
|
+
)
|
|
74
|
+
else {
|
|
63
75
|
return
|
|
64
76
|
}
|
|
65
|
-
|
|
77
|
+
|
|
66
78
|
try scene.initRootView()
|
|
67
79
|
}
|
|
68
80
|
}
|
|
@@ -80,12 +92,14 @@ class HybridCluster: HybridClusterSpec {
|
|
|
80
92
|
[NitroAttributedString]
|
|
81
93
|
) throws {
|
|
82
94
|
if #available(iOS 15.4, *) {
|
|
83
|
-
guard
|
|
84
|
-
|
|
85
|
-
|
|
95
|
+
guard
|
|
96
|
+
let scene = SceneStore.getClusterScene(
|
|
97
|
+
clusterId: clusterId
|
|
98
|
+
)
|
|
99
|
+
else {
|
|
86
100
|
return
|
|
87
101
|
}
|
|
88
|
-
|
|
102
|
+
|
|
89
103
|
scene.setAttributedInactiveDescriptionVariants(
|
|
90
104
|
attributedInactiveDescriptionVariants:
|
|
91
105
|
attributedInactiveDescriptionVariants
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { AppRegistry, Platform } from 'react-native';
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const remove = HybridAutoPlay.addListener('didDisconnect', () => {
|
|
2
|
+
const createTaskProvider = (hybridAutoPlay) => () => () => new Promise((resolve) => {
|
|
3
|
+
const remove = hybridAutoPlay.addListener('didDisconnect', () => {
|
|
5
4
|
resolve();
|
|
6
5
|
remove();
|
|
7
6
|
});
|
|
8
7
|
});
|
|
9
|
-
const registerHeadlessTask = () => {
|
|
8
|
+
const registerHeadlessTask = (hybridAutoPlay) => {
|
|
10
9
|
if (Platform.OS !== 'android') {
|
|
11
10
|
return;
|
|
12
11
|
}
|
|
13
|
-
AppRegistry.registerHeadlessTask('AndroidAutoHeadlessJsTask',
|
|
12
|
+
AppRegistry.registerHeadlessTask('AndroidAutoHeadlessJsTask', createTaskProvider(hybridAutoPlay));
|
|
14
13
|
};
|
|
15
14
|
export default { registerHeadlessTask };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import type { SafeAreaInsets } from '..';
|
|
3
3
|
export declare const SafeAreaInsetsContext: React.Context<SafeAreaInsets>;
|
|
4
4
|
export declare function SafeAreaInsetsProvider({ children, moduleName, }: {
|
|
5
5
|
children: React.ReactNode;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, useEffect, useState } from 'react';
|
|
3
|
-
import { HybridAutoPlay } from '
|
|
3
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
4
4
|
const DEFAULT = { top: 0, bottom: 0, left: 0, right: 0 };
|
|
5
5
|
export const SafeAreaInsetsContext = createContext(DEFAULT);
|
|
6
6
|
export function SafeAreaInsetsProvider({ children, moduleName, }) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
import { PermissionsAndroid } from 'react-native';
|
|
3
|
-
import { HybridAndroidAutoTelemetry
|
|
3
|
+
import { HybridAndroidAutoTelemetry } from '../hybrid/HybridAndroidAutoTelemetry';
|
|
4
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
4
5
|
/**
|
|
5
6
|
* Hook to check if the telemetry permissions are granted. If the permissions are not granted, it will request them from the user.
|
|
6
7
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { HybridAutoPlay } from '
|
|
2
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
3
3
|
/**
|
|
4
4
|
* An effect hook that only runs when the CarPlay/Android Auto screen is visible to the user and dependencies have changed.
|
|
5
5
|
* It behaves like `useEffect`, but the effect function is only executed if the screen is visible.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
-
import { HybridAutoPlay } from '
|
|
2
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
3
3
|
export const useVoiceInput = () => {
|
|
4
4
|
const [isConnected, setIsConnected] = useState(false);
|
|
5
5
|
const [voiceInputResult, setVoiceInputResult] = useState();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const HybridAndroidAutoTelemetry = null;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { HybridAndroidAutoTelemetry } from './hybrid/HybridAndroidAutoTelemetry';
|
|
2
|
+
import { HybridAutoPlay } from './hybrid/HybridAutoPlay';
|
|
1
3
|
import type { AndroidAutomotive } from './specs/AndroidAutomotive.nitro';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export declare const HybridAutoPlay: NitroAutoPlay;
|
|
5
|
-
export declare const HybridAndroidAutoTelemetry: NitroAndroidAutoTelemetry | null;
|
|
4
|
+
export { HybridAutoPlay };
|
|
5
|
+
export { HybridAndroidAutoTelemetry };
|
|
6
6
|
export declare const HybridAndroidAutomotive: AndroidAutomotive | null;
|
|
7
7
|
/**
|
|
8
8
|
* These are the static module names for the app running on the mobile device, head unit screen and the CarPlay dashboard.
|
package/lib/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Platform } from 'react-native';
|
|
2
2
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
3
3
|
import AutoPlayHeadlessJsTask from './AutoPlayHeadlessJsTask';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
import { HybridAndroidAutoTelemetry } from './hybrid/HybridAndroidAutoTelemetry';
|
|
5
|
+
import { HybridAutoPlay } from './hybrid/HybridAutoPlay';
|
|
6
|
+
AutoPlayHeadlessJsTask.registerHeadlessTask(HybridAutoPlay);
|
|
7
|
+
export { HybridAutoPlay };
|
|
8
|
+
export { HybridAndroidAutoTelemetry };
|
|
9
9
|
export const HybridAndroidAutomotive = Platform.OS === 'android'
|
|
10
10
|
? NitroModules.createHybridObject('AndroidAutomotive')
|
|
11
11
|
: null;
|
|
@@ -27,9 +27,9 @@ declare class Dashboard {
|
|
|
27
27
|
* @param eventType generic events
|
|
28
28
|
* @returns callback to remove the listener
|
|
29
29
|
*/
|
|
30
|
-
addListener(event: EventName, callback: () => void): import("
|
|
31
|
-
addListenerRenderState(callback: (payload: VisibilityState) => void): import("
|
|
32
|
-
addListenerColorScheme(callback: (payload: ColorScheme) => void): import("
|
|
30
|
+
addListener(event: EventName, callback: () => void): import("../types/Event").CleanupCallback;
|
|
31
|
+
addListenerRenderState(callback: (payload: VisibilityState) => void): import("../types/Event").CleanupCallback;
|
|
32
|
+
addListenerColorScheme(callback: (payload: ColorScheme) => void): import("../types/Event").CleanupCallback;
|
|
33
33
|
}
|
|
34
34
|
export declare const CarPlayDashboard: Dashboard;
|
|
35
35
|
export {};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { AppRegistry, Platform } from 'react-native';
|
|
3
3
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
4
|
-
import { HybridAutoPlay } from '..';
|
|
5
4
|
import { SafeAreaInsetsProvider } from '../components/SafeAreaInsetsContext';
|
|
5
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
6
6
|
import { NitroImageUtil } from '../utils/NitroImage';
|
|
7
7
|
const HybridCarPlayDashboard = Platform.OS === 'ios'
|
|
8
8
|
? NitroModules.createHybridObject('CarPlayDashboard')
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import type { AutoText } from '..';
|
|
3
3
|
import type { ActionButtonAndroid, MapButton, MapPanButton } from '../types/Button';
|
|
4
4
|
import type { AutoManeuver } from '../types/Maneuver';
|
|
5
5
|
import type { ColorScheme, RootComponentInitialProps } from '../types/RootComponent';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { AppRegistry, Platform } from 'react-native';
|
|
3
3
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
4
|
-
import { HybridAutoPlay } from '..';
|
|
5
4
|
import { MapTemplateProvider } from '../components/MapTemplateContext';
|
|
6
5
|
import { SafeAreaInsetsProvider } from '../components/SafeAreaInsetsContext';
|
|
6
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
7
7
|
import { NitroActionUtil } from '../utils/NitroAction';
|
|
8
8
|
import { NitroAlertUtil } from '../utils/NitroAlert';
|
|
9
9
|
import { NitroManeuverUtil } from '../utils/NitroManeuver';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AutoImage, BaseMapTemplateConfig, CustomActionButtonAndroid, HeaderActionsAndroid, TextButton } from '..';
|
|
2
2
|
import type { AutoText } from '../types/Text';
|
|
3
3
|
import { type NitroAction } from '../utils/NitroAction';
|
|
4
4
|
import { type NitroImage } from '../utils/NitroImage';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Platform } from 'react-native';
|
|
2
2
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
3
3
|
import uuid from 'react-native-uuid';
|
|
4
|
-
import { HybridAutoPlay
|
|
4
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
5
5
|
import { NitroActionUtil } from '../utils/NitroAction';
|
|
6
6
|
import { NitroImageUtil } from '../utils/NitroImage';
|
|
7
7
|
import { NitroMapButton } from '../utils/NitroMapButton';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iternio/react-native-auto-play",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "Android Auto and Apple CarPlay for react-native",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"module": "lib/index",
|
|
@@ -36,8 +36,9 @@
|
|
|
36
36
|
"typescript": "tsc",
|
|
37
37
|
"generate:fonts": "node ./assets/symbolFont/bundleAsset.js",
|
|
38
38
|
"specs": "nitrogen --logLevel=\"debug\"",
|
|
39
|
-
"prepare": "tsc && nitrogen && npm run generate:fonts",
|
|
40
|
-
"swift:format": "swift-format format ./ios --in-place --recursive"
|
|
39
|
+
"prepare": "yarn circular && tsc && nitrogen && npm run generate:fonts",
|
|
40
|
+
"swift:format": "swift-format format ./ios --in-place --recursive",
|
|
41
|
+
"circular": "dpdm ./src/* --circular --exit-code circular:1 --no-tree --warning=false --transform"
|
|
41
42
|
},
|
|
42
43
|
"keywords": [
|
|
43
44
|
"react-native",
|
|
@@ -59,7 +60,8 @@
|
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
62
|
"@types/jest": "^29.5.12",
|
|
62
|
-
"@types/react": "
|
|
63
|
+
"@types/react": "~19.2.0",
|
|
64
|
+
"dpdm": "^4.0.1",
|
|
63
65
|
"nitrogen": "^0.35.3",
|
|
64
66
|
"typescript": "^5.8.3"
|
|
65
67
|
},
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import { AppRegistry, Platform, type Task, type TaskProvider } from 'react-native';
|
|
2
|
-
import {
|
|
2
|
+
import type { AutoPlay as NitroAutoPlay } from './specs/AutoPlay.nitro';
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
const createTaskProvider =
|
|
5
|
+
(hybridAutoPlay: NitroAutoPlay): TaskProvider =>
|
|
6
|
+
(): Task =>
|
|
7
|
+
() =>
|
|
8
|
+
new Promise((resolve) => {
|
|
9
|
+
const remove = hybridAutoPlay.addListener('didDisconnect', () => {
|
|
10
|
+
resolve();
|
|
11
|
+
remove();
|
|
12
|
+
});
|
|
9
13
|
});
|
|
10
|
-
});
|
|
11
14
|
|
|
12
|
-
const registerHeadlessTask = () => {
|
|
15
|
+
const registerHeadlessTask = (hybridAutoPlay: NitroAutoPlay) => {
|
|
13
16
|
if (Platform.OS !== 'android') {
|
|
14
17
|
return;
|
|
15
18
|
}
|
|
16
|
-
AppRegistry.registerHeadlessTask('AndroidAutoHeadlessJsTask',
|
|
19
|
+
AppRegistry.registerHeadlessTask('AndroidAutoHeadlessJsTask', createTaskProvider(hybridAutoPlay));
|
|
17
20
|
};
|
|
18
21
|
|
|
19
22
|
export default { registerHeadlessTask };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import { createContext, useEffect, useState } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import type { SafeAreaInsets } from '..';
|
|
4
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
4
5
|
|
|
5
6
|
const DEFAULT: SafeAreaInsets = { top: 0, bottom: 0, left: 0, right: 0 };
|
|
6
7
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
import { type Permission, PermissionsAndroid } from 'react-native';
|
|
3
|
-
import { HybridAndroidAutoTelemetry
|
|
3
|
+
import { HybridAndroidAutoTelemetry } from '../hybrid/HybridAndroidAutoTelemetry';
|
|
4
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
4
5
|
|
|
5
6
|
import type { AndroidAutoPermissions, Telemetry } from '../types/Telemetry';
|
|
6
7
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { HybridAutoPlay } from '
|
|
2
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* An effect hook that only runs when the CarPlay/Android Auto screen is visible to the user and dependencies have changed.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import type { Location } from '..';
|
|
3
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
3
4
|
|
|
4
5
|
export const useVoiceInput = () => {
|
|
5
6
|
const [isConnected, setIsConnected] = useState(false);
|
package/src/index.ts
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import { Platform } from 'react-native';
|
|
2
2
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
3
3
|
import AutoPlayHeadlessJsTask from './AutoPlayHeadlessJsTask';
|
|
4
|
+
import { HybridAndroidAutoTelemetry } from './hybrid/HybridAndroidAutoTelemetry';
|
|
5
|
+
import { HybridAutoPlay } from './hybrid/HybridAutoPlay';
|
|
4
6
|
import type { AndroidAutomotive } from './specs/AndroidAutomotive.nitro';
|
|
5
|
-
import type { AndroidAutoTelemetry as NitroAndroidAutoTelemetry } from './specs/AndroidAutoTelemetry.nitro';
|
|
6
|
-
import type { AutoPlay as NitroAutoPlay } from './specs/AutoPlay.nitro';
|
|
7
7
|
|
|
8
|
-
AutoPlayHeadlessJsTask.registerHeadlessTask();
|
|
8
|
+
AutoPlayHeadlessJsTask.registerHeadlessTask(HybridAutoPlay);
|
|
9
9
|
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
export const HybridAndroidAutoTelemetry =
|
|
13
|
-
Platform.OS === 'android'
|
|
14
|
-
? NitroModules.createHybridObject<NitroAndroidAutoTelemetry>('AndroidAutoTelemetry')
|
|
15
|
-
: null;
|
|
10
|
+
export { HybridAutoPlay };
|
|
11
|
+
export { HybridAndroidAutoTelemetry };
|
|
16
12
|
|
|
17
13
|
export const HybridAndroidAutomotive =
|
|
18
14
|
Platform.OS === 'android'
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { AppRegistry, Platform } from 'react-native';
|
|
3
3
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
4
|
-
import { HybridAutoPlay } from '..';
|
|
5
4
|
import { SafeAreaInsetsProvider } from '../components/SafeAreaInsetsContext';
|
|
5
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
6
6
|
import type {
|
|
7
7
|
BaseCarPlayDashboardButton,
|
|
8
8
|
CarPlayDashboard as NitroCarPlayDashboard,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { AppRegistry, Platform } from 'react-native';
|
|
3
3
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
4
|
-
import {
|
|
4
|
+
import type { AutoText } from '..';
|
|
5
5
|
import { MapTemplateProvider } from '../components/MapTemplateContext';
|
|
6
6
|
import { SafeAreaInsetsProvider } from '../components/SafeAreaInsetsContext';
|
|
7
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
7
8
|
import type { MapTemplate as NitroMapTemplate } from '../specs/MapTemplate.nitro';
|
|
8
9
|
import type { ActionButtonAndroid, MapButton, MapPanButton } from '../types/Button';
|
|
9
10
|
import type { AutoManeuver } from '../types/Maneuver';
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Platform } from 'react-native';
|
|
2
2
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
3
3
|
import uuid from 'react-native-uuid';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
type TextButton,
|
|
4
|
+
import type {
|
|
5
|
+
AutoImage,
|
|
6
|
+
BaseMapTemplateConfig,
|
|
7
|
+
CustomActionButtonAndroid,
|
|
8
|
+
HeaderActionsAndroid,
|
|
9
|
+
TextButton,
|
|
11
10
|
} from '..';
|
|
11
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
12
12
|
import type { MessageTemplate as NitroMessageTemplate } from '../specs/MessageTemplate.nitro';
|
|
13
13
|
import type { AutoText } from '../types/Text';
|
|
14
14
|
import { type NitroAction, NitroActionUtil } from '../utils/NitroAction';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import uuid from 'react-native-uuid';
|
|
2
|
-
import { HybridAutoPlay } from '
|
|
2
|
+
import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
|
|
3
3
|
import type { ActionButtonAndroid, ActionButtonIos, AppButton, BackButton } from '../types/Button';
|
|
4
4
|
import { type NitroAction, NitroActionUtil } from '../utils/NitroAction';
|
|
5
5
|
import type { NitroMapButton } from '../utils/NitroMapButton';
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
package com.margelo.nitro.swe.iternio.reactnativeautoplay.utils
|
|
2
|
-
|
|
3
|
-
import com.facebook.react.ReactApplication
|
|
4
|
-
import com.facebook.react.ReactInstanceEventListener
|
|
5
|
-
import com.facebook.react.bridge.ReactContext
|
|
6
|
-
import kotlinx.coroutines.suspendCancellableCoroutine
|
|
7
|
-
import kotlin.coroutines.resume
|
|
8
|
-
|
|
9
|
-
object ReactContextResolver {
|
|
10
|
-
suspend fun getReactContext(application: ReactApplication): ReactContext {
|
|
11
|
-
val host =
|
|
12
|
-
application.reactHost ?: throw IllegalArgumentException("application host null")
|
|
13
|
-
|
|
14
|
-
return suspendCancellableCoroutine { continuation ->
|
|
15
|
-
host.currentReactContext?.let {
|
|
16
|
-
continuation.resume(it)
|
|
17
|
-
return@suspendCancellableCoroutine
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
val listener = object : ReactInstanceEventListener {
|
|
21
|
-
override fun onReactContextInitialized(context: ReactContext) {
|
|
22
|
-
host.removeReactInstanceEventListener(this)
|
|
23
|
-
continuation.resume(context)
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
host.addReactInstanceEventListener(listener)
|
|
27
|
-
|
|
28
|
-
continuation.invokeOnCancellation {
|
|
29
|
-
host.removeReactInstanceEventListener(listener)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
host.start()
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
}
|