@@ -5,11 +5,13 @@ import android.content.res.Configuration
55import android.content.res.Resources
66import android.location.Location
77import android.os.Bundle
8+ import android.view.View
89import android.view.View.INVISIBLE
910import android.view.View.VISIBLE
1011import android.widget.Toast
1112import androidx.appcompat.app.AppCompatActivity
1213import androidx.core.content.ContextCompat
14+ import androidx.lifecycle.lifecycleScope
1315import com.mapbox.api.directions.v5.models.RouteOptions
1416import com.mapbox.bindgen.Expected
1517import com.mapbox.geojson.Point
@@ -19,8 +21,10 @@ import com.mapbox.maps.MapboxMap
1921import com.mapbox.maps.Style.Companion.MAPBOX_STREETS
2022import com.mapbox.maps.plugin.LocationPuck2D
2123import com.mapbox.maps.plugin.animation.camera
24+ import com.mapbox.maps.plugin.gestures.OnMapClickListener
2225import com.mapbox.maps.plugin.gestures.gestures
2326import com.mapbox.maps.plugin.locationcomponent.location
27+ import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
2428import com.mapbox.navigation.base.TimeFormat
2529import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions
2630import com.mapbox.navigation.base.extensions.applyLanguageAndVoiceUnitOptions
@@ -35,6 +39,7 @@ import com.mapbox.navigation.core.MapboxNavigation
3539import com.mapbox.navigation.core.MapboxNavigationProvider
3640import com.mapbox.navigation.core.directions.session.RoutesObserver
3741import com.mapbox.navigation.core.formatter.MapboxDistanceFormatter
42+ import com.mapbox.navigation.core.preview.RoutesPreviewObserver
3843import com.mapbox.navigation.core.trip.session.LocationMatcherResult
3944import com.mapbox.navigation.core.trip.session.LocationObserver
4045import com.mapbox.navigation.core.trip.session.NavigationSessionStateObserver
@@ -52,11 +57,10 @@ import com.mapbox.navigation.ui.maps.location.NavigationLocationProvider
5257import com.mapbox.navigation.ui.maps.route.arrow.api.MapboxRouteArrowApi
5358import com.mapbox.navigation.ui.maps.route.arrow.api.MapboxRouteArrowView
5459import com.mapbox.navigation.ui.maps.route.arrow.model.RouteArrowOptions
55- import com.mapbox.navigation.ui.maps.route.line.MapboxRouteLineApiExtensions.setRoutes
60+ import com.mapbox.navigation.ui.maps.route.line.MapboxRouteLineApiExtensions.findClosestRoute
5661import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi
5762import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineView
5863import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineOptions
59- import com.mapbox.navigation.ui.maps.route.line.model.RouteLine
6064import com.mapbox.navigation.ui.tripprogress.api.MapboxTripProgressApi
6165import com.mapbox.navigation.ui.tripprogress.model.DistanceRemainingFormatter
6266import com.mapbox.navigation.ui.tripprogress.model.EstimatedTimeToArrivalFormatter
@@ -70,11 +74,10 @@ import com.mapbox.navigation.ui.voice.model.SpeechError
7074import com.mapbox.navigation.ui.voice.model.SpeechValue
7175import com.mapbox.navigation.ui.voice.model.SpeechVolume
7276import com.mapbox.navigation.utils.internal.logD
73- import kotlinx.coroutines.CoroutineScope
74- import kotlinx.coroutines.Dispatchers
7577import kotlinx.coroutines.launch
7678import java.util.Locale
7779
80+ @OptIn(ExperimentalPreviewMapboxNavigationAPI ::class )
7881class MapboxNavigationActivity : AppCompatActivity () {
7982
8083 /* ----- Layout binding reference ----- */
@@ -229,18 +232,17 @@ class MapboxNavigationActivity : AppCompatActivity() {
229232 }
230233
231234 private val routesObserver = RoutesObserver { result ->
232- if (result.routes .isNotEmpty()) {
235+ if (result.navigationRoutes .isNotEmpty()) {
233236 // generate route geometries asynchronously and render them
234- CoroutineScope ( Dispatchers . Main ).launch {
235- val result = routeLineAPI.setRoutes(
236- listOf ( RouteLine ( result.routes.first(), null ) )
237- )
237+ routeLineAPI.setNavigationRoutes(
238+ result.navigationRoutes,
239+ mapboxNavigation.getAlternativeMetadataFor( result.navigationRoutes )
240+ ) {
238241 val style = mapboxMap.getStyle()
239242 if (style != null ) {
240- routeLineView.renderRouteDrawData(style, result )
243+ routeLineView.renderRouteDrawData(style, it )
241244 }
242245 }
243-
244246 // update the camera position to account for the new route
245247 viewportDataSource.onRouteChanged(result.routes.first())
246248 viewportDataSource.evaluate()
@@ -263,11 +265,48 @@ class MapboxNavigationActivity : AppCompatActivity() {
263265 }
264266 }
265267
268+ private val routesPreviewObserver = RoutesPreviewObserver { update ->
269+ val routePreview = update.routesPreview
270+ if (routePreview != null ) {
271+ routeLineAPI.setNavigationRoutes(
272+ routePreview.routesList,
273+ routePreview.alternativesMetadata
274+ ) {
275+ val style = mapboxMap.getStyle()
276+ if (style != null ) {
277+ routeLineView.renderRouteDrawData(style, it)
278+ }
279+ }
280+ // update the camera position to account for the new route
281+ viewportDataSource.onRouteChanged(routePreview.primaryRoute)
282+ viewportDataSource.evaluate()
283+ }
284+ }
285+
266286 private val navigationSessionStateObserver = NavigationSessionStateObserver {
267287 logD(" NavigationSessionState=$it " , LOG_CATEGORY )
268288 logD(" sessionId=${mapboxNavigation.getNavigationSessionState().sessionId} " , LOG_CATEGORY )
269289 }
270290
291+ private val routeClickPadding = com.mapbox.android.gestures.Utils .dpToPx(30f )
292+
293+ private val previewMapClickListener = OnMapClickListener {
294+ lifecycleScope.launch {
295+ mapboxNavigation.getRoutesPreview() ? : return @launch
296+ val result = routeLineAPI.findClosestRoute(
297+ it,
298+ binding.mapView.getMapboxMap(),
299+ routeClickPadding
300+ )
301+
302+ val routeFound = result.value?.navigationRoute
303+ if (routeFound != null && routeFound != routeLineAPI.getPrimaryNavigationRoute()) {
304+ mapboxNavigation.changeRoutesPreviewPrimaryRoute(routeFound)
305+ }
306+ }
307+ false
308+ }
309+
271310 @SuppressLint(" MissingPermission" )
272311 override fun onCreate (savedInstanceState : Bundle ? ) {
273312 super .onCreate(savedInstanceState)
@@ -401,6 +440,7 @@ class MapboxNavigationActivity : AppCompatActivity() {
401440 findRoute(point)
402441 true
403442 }
443+ binding.mapView.gestures.addOnMapClickListener(previewMapClickListener)
404444 }
405445
406446 // initialize view interactions
@@ -438,6 +478,7 @@ class MapboxNavigationActivity : AppCompatActivity() {
438478 mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
439479 mapboxNavigation.registerLocationObserver(locationObserver)
440480 mapboxNavigation.registerVoiceInstructionsObserver(voiceInstructionsObserver)
481+ mapboxNavigation.registerRoutesPreviewObserver(routesPreviewObserver)
441482 }
442483
443484 override fun onStop () {
@@ -447,6 +488,7 @@ class MapboxNavigationActivity : AppCompatActivity() {
447488 mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver)
448489 mapboxNavigation.unregisterLocationObserver(locationObserver)
449490 mapboxNavigation.unregisterVoiceInstructionsObserver(voiceInstructionsObserver)
491+ mapboxNavigation.unregisterRoutesPreviewObserver(routesPreviewObserver)
450492 }
451493
452494 override fun onDestroy () {
@@ -468,6 +510,7 @@ class MapboxNavigationActivity : AppCompatActivity() {
468510 RouteOptions .builder()
469511 .applyDefaultNavigationOptions()
470512 .applyLanguageAndVoiceUnitOptions(this )
513+ .alternatives(true )
471514 .coordinatesList(listOf (origin, destination))
472515 .layersList(listOf (mapboxNavigation.getZLevel(), null ))
473516 .build(),
@@ -476,7 +519,7 @@ class MapboxNavigationActivity : AppCompatActivity() {
476519 routes : List <NavigationRoute >,
477520 routerOrigin : RouterOrigin
478521 ) {
479- setRouteAndStartNavigation (routes)
522+ setRoutesPreview (routes)
480523 }
481524
482525 override fun onFailure (
@@ -493,6 +536,18 @@ class MapboxNavigationActivity : AppCompatActivity() {
493536 )
494537 }
495538
539+ private fun setRoutesPreview (routes : List <NavigationRoute >) {
540+ binding.navigateButton.apply {
541+ visibility = View .VISIBLE
542+ setOnClickListener {
543+ visibility = View .GONE
544+ setRouteAndStartNavigation(mapboxNavigation.getRoutesPreview()!! .routesList)
545+ mapboxNavigation.setRoutesPreview(emptyList())
546+ }
547+ }
548+ mapboxNavigation.setRoutesPreview(routes)
549+ }
550+
496551 private fun setRouteAndStartNavigation (route : List <NavigationRoute >) {
497552 // set route
498553 mapboxNavigation.setNavigationRoutes(route)
0 commit comments