fix: Custom navigation events

This commit is contained in:
Piotr Dec 2024-08-09 01:25:35 +02:00
parent 65cdeb17d0
commit ffbd7c46b8
Signed by: stawros
GPG key ID: F89F27AD8F881A91
5 changed files with 97 additions and 27 deletions

View file

@ -4,6 +4,7 @@ import android.content.res.Configuration
import android.content.res.Resources
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.mapbox.geojson.Point
import com.mapbox.maps.ImageHolder
import com.mapbox.maps.plugin.LocationPuck2D
import com.mapbox.maps.plugin.animation.camera
@ -48,6 +49,8 @@ class MapControl(
*/
val navigationLocationProvider = NavigationLocationProvider()
val navigationStatusControl = NavigationStatusControl()
val replay = ReplayResources(this)
// Observers
@ -59,7 +62,6 @@ class MapControl(
private lateinit var routeProgressObserver: RouteProgressObserver
private lateinit var voiceInstructionsObserver: VoiceInstructionsObserver
private val searchControl = SearchControl(this, ui)
private val navigationStateListener = NavigationStateListener()
fun init() {
viewportDataSource = MapboxNavigationViewportDataSource(ui.mapView.mapboxMap)
@ -105,6 +107,10 @@ class MapControl(
voiceInstructionsObserver = voiceControl.voiceInstructionsObserver
}
fun routeToPoint(point: Point) {
routeControl.findRoute(point)
}
fun initNavigation() {
MapboxNavigationApp.setup(
NavigationOptions.Builder(context)
@ -135,7 +141,8 @@ class MapControl(
mapboxNavigation.registerLocationObserver(locationObserver)
mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
mapboxNavigation.registerVoiceInstructionsObserver(voiceInstructionsObserver)
mapboxNavigation.registerNavigationSessionStateObserver(navigationStateListener)
navigationStatusControl.registerObserver(searchControl)
replay.onAttached(mapboxNavigation)
}
@ -145,7 +152,8 @@ class MapControl(
mapboxNavigation.unregisterLocationObserver(locationObserver)
mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver)
mapboxNavigation.unregisterVoiceInstructionsObserver(voiceInstructionsObserver)
mapboxNavigation.unregisterNavigationSessionStateObserver(navigationStateListener)
navigationStatusControl.unregisterObserver(searchControl)
replay.onDetached(mapboxNavigation)
}

View file

@ -1,12 +0,0 @@
package eu.ztsh.garmin.mapbox
import com.mapbox.navigation.core.trip.session.NavigationSessionState
import com.mapbox.navigation.core.trip.session.NavigationSessionStateObserver
class NavigationStateListener: NavigationSessionStateObserver {
override fun onNavigationSessionStateChanged(navigationSession: NavigationSessionState) {
// TODO("Not yet implemented")
}
}

View file

@ -0,0 +1,49 @@
package eu.ztsh.garmin.mapbox
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import java.util.concurrent.CopyOnWriteArraySet
import java.util.concurrent.atomic.AtomicReference
class NavigationStatusControl {
private val stateObservers = CopyOnWriteArraySet<NavigationStatusObserver>()
private val current = AtomicReference(NavigationStatus.IDLE)
fun registerObserver(observer: NavigationStatusObserver) {
stateObservers.add(observer)
observer.onNavigationStatusChanged(current.get())
}
fun unregisterObserver(observer: NavigationStatusObserver) {
stateObservers.remove(observer)
}
fun sendEvent(status: NavigationStatus) {
current.set(status)
stateObservers.forEach {
it.onNavigationStatusChanged(status)
}
if (status == NavigationStatus.FINISHED || status == NavigationStatus.CANCELED) {
// TODO: lifecyclescope?
runBlocking {
delay(1000)
sendEvent(NavigationStatus.IDLE)
}
}
}
}
enum class NavigationStatus {
IDLE,
STARTED,
FINISHED,
CANCELED
}
fun interface NavigationStatusObserver {
fun onNavigationStatusChanged(navigationStatus: NavigationStatus)
}

View file

@ -3,10 +3,10 @@ package eu.ztsh.garmin.mapbox
import android.content.Context
import android.view.View
import android.widget.Toast
import androidx.lifecycle.lifecycleScope
import com.mapbox.api.directions.v5.models.Bearing
import com.mapbox.api.directions.v5.models.RouteOptions
import com.mapbox.geojson.Point
import com.mapbox.maps.plugin.gestures.gestures
import com.mapbox.navigation.base.TimeFormat
import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions
import com.mapbox.navigation.base.extensions.applyLanguageAndVoiceUnitOptions
@ -37,6 +37,10 @@ import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineApiOptions
import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineViewOptions
import eu.ztsh.garmin.Garmin
import eu.ztsh.garmin.UI
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
class RouteControl(private val mapControl: MapControl, ui: UI, private val context: Context) {
@ -115,11 +119,6 @@ class RouteControl(private val mapControl: MapControl, ui: UI, private val conte
// Ensure that the route line related layers are present before the route arrow
routeLineView.initializeLayers(it)
// add long click listener that search for a route to the clicked destination
// ui.mapView.gestures.addOnMapLongClickListener { point ->
// findRoute(point)
// true
// }
}
// initialize view interactions
@ -219,7 +218,7 @@ class RouteControl(private val mapControl: MapControl, ui: UI, private val conte
}
}
private fun findRoute(destination: Point) {
fun findRoute(destination: Point) {
val originLocation = mapControl.navigationLocationProvider.lastLocation ?: return
val originPoint = Point.fromLngLat(originLocation.longitude, originLocation.latitude)
@ -284,6 +283,15 @@ class RouteControl(private val mapControl: MapControl, ui: UI, private val conte
// start simulation
mapControl.replay.startSimulation(routes.first().directionsRoute)
mapControl.context.apply {
lifecycleScope.launch {
async {
delay(5000)
mapControl.navigationCamera.requestNavigationCameraToFollowing()
}
}
}
}
private fun clearRouteAndStopNavigation() {
@ -298,6 +306,9 @@ class RouteControl(private val mapControl: MapControl, ui: UI, private val conte
mapControl.ui.maneuverView.visibility = View.INVISIBLE
mapControl.ui.routeOverview.visibility = View.INVISIBLE
mapControl.ui.tripProgressCard.visibility = View.INVISIBLE
// post custom event
mapControl.navigationStatusControl.sendEvent(NavigationStatus.CANCELED)
}
fun cancel() {

View file

@ -21,6 +21,7 @@ import com.mapbox.maps.plugin.annotation.annotations
import com.mapbox.maps.plugin.annotation.generated.CircleAnnotationOptions
import com.mapbox.maps.plugin.annotation.generated.createCircleAnnotationManager
import com.mapbox.maps.plugin.gestures.gestures
import com.mapbox.navigation.core.trip.session.NavigationSessionState
import com.mapbox.search.autocomplete.PlaceAutocomplete
import com.mapbox.search.autocomplete.PlaceAutocompleteOptions
import com.mapbox.search.autocomplete.PlaceAutocompleteSuggestion
@ -33,7 +34,7 @@ import eu.ztsh.garmin.R
import eu.ztsh.garmin.UI
import kotlinx.coroutines.launch
class SearchControl(val mapControl: MapControl, val ui: UI) {
class SearchControl(val mapControl: MapControl, val ui: UI): NavigationStatusObserver {
// Set your Access Token here if it's not already set in some other way
// MapboxOptions.accessToken = "<my-access-token>"
@ -86,13 +87,12 @@ class SearchControl(val mapControl: MapControl, val ui: UI) {
}
addOnNavigateClickListener { searchPlace ->
showToast(R.string.not_implemented_yet)
// startActivity(geoIntent(searchPlace.coordinate))
mapControl.routeToPoint(searchPlace.coordinate)
mapControl.navigationStatusControl.sendEvent(NavigationStatus.STARTED)
}
addOnShareClickListener { searchPlace ->
addOnShareClickListener { _ ->
showToast(R.string.not_implemented_yet)
// startActivity(shareIntent(searchPlace))
}
}
@ -182,6 +182,20 @@ class SearchControl(val mapControl: MapControl, val ui: UI) {
}
}
override fun onNavigationStatusChanged(navigationStatus: NavigationStatus) {
when (navigationStatus) {
NavigationStatus.IDLE -> {
ui.queryEditText.visibility = View.VISIBLE
}
NavigationStatus.STARTED -> {
mapControl.navigationCamera.requestNavigationCameraToOverview()
closePlaceCard()
ui.queryEditText.visibility = View.GONE
}
else -> {}
}
}
private fun showToast(@StringRes resId: Int): Unit =
Toast.makeText(mapControl.context, resId, Toast.LENGTH_LONG).show()