From ffbd7c46b8046cbb9a27d9928d9dbd9787a63646 Mon Sep 17 00:00:00 2001 From: Piotr Dec Date: Fri, 9 Aug 2024 01:25:35 +0200 Subject: [PATCH] fix: Custom navigation events --- .../java/eu/ztsh/garmin/mapbox/MapControl.kt | 14 ++++-- .../garmin/mapbox/NavigationStateListener.kt | 12 ----- .../eu/ztsh/garmin/mapbox/NavigationStatus.kt | 49 +++++++++++++++++++ .../eu/ztsh/garmin/mapbox/RouteControl.kt | 25 +++++++--- .../eu/ztsh/garmin/mapbox/SearchControl.kt | 24 +++++++-- 5 files changed, 97 insertions(+), 27 deletions(-) delete mode 100644 app/src/main/java/eu/ztsh/garmin/mapbox/NavigationStateListener.kt create mode 100644 app/src/main/java/eu/ztsh/garmin/mapbox/NavigationStatus.kt diff --git a/app/src/main/java/eu/ztsh/garmin/mapbox/MapControl.kt b/app/src/main/java/eu/ztsh/garmin/mapbox/MapControl.kt index 5c5429b..f3f4082 100644 --- a/app/src/main/java/eu/ztsh/garmin/mapbox/MapControl.kt +++ b/app/src/main/java/eu/ztsh/garmin/mapbox/MapControl.kt @@ -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) } diff --git a/app/src/main/java/eu/ztsh/garmin/mapbox/NavigationStateListener.kt b/app/src/main/java/eu/ztsh/garmin/mapbox/NavigationStateListener.kt deleted file mode 100644 index e4c5b67..0000000 --- a/app/src/main/java/eu/ztsh/garmin/mapbox/NavigationStateListener.kt +++ /dev/null @@ -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") - } - -} \ No newline at end of file diff --git a/app/src/main/java/eu/ztsh/garmin/mapbox/NavigationStatus.kt b/app/src/main/java/eu/ztsh/garmin/mapbox/NavigationStatus.kt new file mode 100644 index 0000000..468a697 --- /dev/null +++ b/app/src/main/java/eu/ztsh/garmin/mapbox/NavigationStatus.kt @@ -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() + 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) + +} \ No newline at end of file diff --git a/app/src/main/java/eu/ztsh/garmin/mapbox/RouteControl.kt b/app/src/main/java/eu/ztsh/garmin/mapbox/RouteControl.kt index ecdb76b..b0e755e 100644 --- a/app/src/main/java/eu/ztsh/garmin/mapbox/RouteControl.kt +++ b/app/src/main/java/eu/ztsh/garmin/mapbox/RouteControl.kt @@ -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() { diff --git a/app/src/main/java/eu/ztsh/garmin/mapbox/SearchControl.kt b/app/src/main/java/eu/ztsh/garmin/mapbox/SearchControl.kt index 94a2b74..ef867f2 100644 --- a/app/src/main/java/eu/ztsh/garmin/mapbox/SearchControl.kt +++ b/app/src/main/java/eu/ztsh/garmin/mapbox/SearchControl.kt @@ -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 = "" @@ -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()