diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f04587babf..e46c555e4b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,16 @@ Mapbox welcomes participation and contributions from everyone. #### Bug fixes and improvements - Updated `NavigationView` to render upcoming maneuvers. [#6175](https://github.com/mapbox/mapbox-navigation-android/pull/6175) - Updated `NavigationView` to allow drawing of the info panel behind the translucent navigation bar. [#6145](https://github.com/mapbox/mapbox-navigation-android/pull/6145) -- Fixed an issue where `NavigationView` switches from Active Guidance to Free Drive state after rotating device when replay is enabled. [#6140](https://github.com/mapbox/mapbox-navigation-android/pull/6140) +- Fixed an issue where `NavigationView` switches from Active Guidance to Free Drive state after rotating device when replay is enabled. [#6140](https://github.com/mapbox/mapbox-navigation-android/pull/6140) +- Improved inactive leg independent styling: now the inactive leg will be styled differently right away, not only when the route progress updates begin. +- Added `MapboxNavigation#currentLegIndex`. Use this method to correctly pass leg index to `MapboxRouteLineAPI#setNavigationRoutes` method, this is especially important if you use independent inactive leg styling: +```kotlin +val routesObserver = RoutesObserver { + routeLineAPI.setNavigationRoutes(result.navigationRoutes, mapboxNavigation.currentLegIndex()).apply { + routeLineView.renderRouteDrawData(mapboxMap.getStyle()!!, this) + } +} +``` ## Mapbox Navigation SDK 2.7.0 - 17 August, 2022 ### Changelog diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 0ba5b41c771..cacad046899 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -13,7 +13,7 @@ ext { // version which we should use in this build def mapboxNavigatorVersion = System.getenv("FORCE_MAPBOX_NAVIGATION_NATIVE_VERSION") if (mapboxNavigatorVersion == null || mapboxNavigatorVersion == '') { - mapboxNavigatorVersion = '111.0.0' + mapboxNavigatorVersion = '111.0.0-backports.2' } println("Navigation Native version: " + mapboxNavigatorVersion) diff --git a/libnavigation-core/src/main/java/com/mapbox/navigation/core/MapboxNavigation.kt b/libnavigation-core/src/main/java/com/mapbox/navigation/core/MapboxNavigation.kt index 8b56ae5a389..8c634e0f636 100644 --- a/libnavigation-core/src/main/java/com/mapbox/navigation/core/MapboxNavigation.kt +++ b/libnavigation-core/src/main/java/com/mapbox/navigation/core/MapboxNavigation.kt @@ -854,6 +854,16 @@ class MapboxNavigation @VisibleForTesting internal constructor( CacheHandleWrapper.requestRoadGraphDataUpdate(navigator.cache, callback) } + /** + * Returns leg index the user is currently on. If no RouteProgress updates are available, + * returns the value passed as `initialLegIndex` parameter to `setNavigationRoutes`. + * If no routes are set, returns 0. + */ + fun currentLegIndex(): Int { + return tripSession.getRouteProgress()?.currentLegProgress?.legIndex + ?: directionsSession.initialLegIndex + } + private fun internalSetNavigationRoutes( routes: List, legIndex: Int = 0, diff --git a/libnavui-maps/api/current.txt b/libnavui-maps/api/current.txt index 2c02452d482..5b087551001 100644 --- a/libnavui-maps/api/current.txt +++ b/libnavui-maps/api/current.txt @@ -807,9 +807,13 @@ package com.mapbox.navigation.ui.maps.route.line { method public com.mapbox.bindgen.Expected setAlternativeTrafficColor(com.mapbox.bindgen.Expected, @ColorInt int color); method public com.mapbox.bindgen.Expected setAlternativeTrafficColor(com.mapbox.bindgen.Expected, com.mapbox.maps.extension.style.expressions.generated.Expression expression); method public suspend Object? setNavigationRouteLines(com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi, java.util.List newRoutes, kotlin.coroutines.Continuation>); + method public suspend Object? setNavigationRouteLines(com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi, java.util.List newRoutes, int activeLegIndex, kotlin.coroutines.Continuation>); method public suspend Object? setNavigationRouteLines(com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi, java.util.List newRoutes, java.util.List alternativeRoutesMetadata, kotlin.coroutines.Continuation>); + method public suspend Object? setNavigationRouteLines(com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi, java.util.List newRoutes, int activeLegIndex, java.util.List alternativeRoutesMetadata, kotlin.coroutines.Continuation>); method public suspend Object? setNavigationRoutes(com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi, java.util.List newRoutes, kotlin.coroutines.Continuation>); + method public suspend Object? setNavigationRoutes(com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi, java.util.List newRoutes, int activeLegIndex, kotlin.coroutines.Continuation>); method public suspend Object? setNavigationRoutes(com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi, java.util.List newRoutes, java.util.List alternativeRoutesMetadata, kotlin.coroutines.Continuation>); + method public suspend Object? setNavigationRoutes(com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi, java.util.List newRoutes, int activeLegIndex, java.util.List alternativeRoutesMetadata, kotlin.coroutines.Continuation>); method public com.mapbox.bindgen.Expected setPrimaryTrafficColor(com.mapbox.bindgen.Expected, @ColorInt int color); method public com.mapbox.bindgen.Expected setPrimaryTrafficColor(com.mapbox.bindgen.Expected, com.mapbox.maps.extension.style.expressions.generated.Expression expression); method @Deprecated public suspend Object? setRoutes(com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi, java.util.List newRoutes, kotlin.coroutines.Continuation>); @@ -834,8 +838,11 @@ package com.mapbox.navigation.ui.maps.route.line.api { method public double getVanishPointOffset(); method public void setNavigationRouteLines(java.util.List newRoutes, com.mapbox.navigation.ui.base.util.MapboxNavigationConsumer> consumer); method public void setNavigationRouteLines(java.util.List newRoutes, java.util.List alternativeRoutesMetadata, com.mapbox.navigation.ui.base.util.MapboxNavigationConsumer> consumer); + method public void setNavigationRouteLines(java.util.List newRoutes, int activeLegIndex, java.util.List alternativeRoutesMetadata, com.mapbox.navigation.ui.base.util.MapboxNavigationConsumer> consumer); method public void setNavigationRoutes(java.util.List newRoutes, com.mapbox.navigation.ui.base.util.MapboxNavigationConsumer> consumer); + method public void setNavigationRoutes(java.util.List newRoutes, int activeLegIndex, com.mapbox.navigation.ui.base.util.MapboxNavigationConsumer> consumer); method public void setNavigationRoutes(java.util.List newRoutes, java.util.List alternativeRoutesMetadata, com.mapbox.navigation.ui.base.util.MapboxNavigationConsumer> consumer); + method public void setNavigationRoutes(java.util.List newRoutes, int activeLegIndex, java.util.List alternativeRoutesMetadata, com.mapbox.navigation.ui.base.util.MapboxNavigationConsumer> consumer); method public void setRoadClasses(java.util.List roadClasses); method @Deprecated public void setRoutes(java.util.List newRoutes, com.mapbox.navigation.ui.base.util.MapboxNavigationConsumer> consumer); method public com.mapbox.bindgen.Expected setVanishingOffset(double offset); diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt index 78676050ac5..fc1cda87ab6 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt @@ -1332,8 +1332,26 @@ internal object MapboxRouteLineUtils { isPrimaryRoute, colorResources ) - if (useSoftGradient) { - val stopGap = softGradientTransitionDistance / route.distance() + val stopGap = softGradientTransitionDistance / route.distance() + getTrafficLineExpression( + vanishingPointOffset, + lineStartColor, + lineColor, + stopGap, + useSoftGradient, + segments + ) + } + + internal fun getTrafficLineExpression( + vanishingPointOffset: Double, + lineStartColor: Int, + lineColor: Int, + stopGap: Double, + useSoftGradient: Boolean, + segments: List, + ): Expression { + return if (useSoftGradient) { getTrafficLineExpressionSoftGradient( vanishingPointOffset, lineStartColor, diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/MapboxRouteLineApiExtensions.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/MapboxRouteLineApiExtensions.kt index 5cd0dcd6dec..a79bd10d62a 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/MapboxRouteLineApiExtensions.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/MapboxRouteLineApiExtensions.kt @@ -13,6 +13,7 @@ import com.mapbox.navigation.core.routealternatives.AlternativeRouteMetadata import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi import com.mapbox.navigation.ui.maps.route.line.model.ClosestRouteValue +import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineOptions import com.mapbox.navigation.ui.maps.route.line.model.NavigationRouteLine import com.mapbox.navigation.ui.maps.route.line.model.RouteLine import com.mapbox.navigation.ui.maps.route.line.model.RouteLineClearValue @@ -83,6 +84,45 @@ object MapboxRouteLineApiExtensions { * * @param newRoutes one or more routes. The first route in the collection will be considered * the primary route and any additional routes will be alternate routes. + * @param activeLegIndex the index of the currently active leg of the primary route. + * + * @return a state which contains the side effects to be applied to the map + */ + suspend fun MapboxRouteLineApi.setNavigationRouteLines( + newRoutes: List, + activeLegIndex: Int, + ): Expected { + return setNavigationRouteLines( + newRoutes = newRoutes, + activeLegIndex = activeLegIndex, + alternativeRoutesMetadata = emptyList() + ) + } + + /** + * Sets the routes that will be operated on. + * + * @param newRoutes one or more routes. The first route in the collection will be considered + * the primary route and any additional routes will be alternate routes. + * @param alternativeRoutesMetadata if available, the update will hide the portions of the alternative routes + * until the deviation point with the primary route. See [MapboxNavigation.getAlternativeMetadataFor]. + * + * @return a state which contains the side effects to be applied to the map + */ + suspend fun MapboxRouteLineApi.setNavigationRouteLines( + newRoutes: List, + alternativeRoutesMetadata: List + ): Expected { + return setNavigationRouteLines(newRoutes, 0, alternativeRoutesMetadata) + } + + /** + * Sets the routes that will be operated on. + * + * @param newRoutes one or more routes. The first route in the collection will be considered + * the primary route and any additional routes will be alternate routes. + * @param activeLegIndex the index of the currently active leg of the primary route. + * This is used when [MapboxRouteLineOptions.styleInactiveRouteLegsIndependently] is enabled. * @param alternativeRoutesMetadata if available, the update will hide the portions of the alternative routes * until the deviation point with the primary route. See [MapboxNavigation.getAlternativeMetadataFor]. * @@ -90,11 +130,13 @@ object MapboxRouteLineApiExtensions { */ suspend fun MapboxRouteLineApi.setNavigationRouteLines( newRoutes: List, + activeLegIndex: Int, alternativeRoutesMetadata: List ): Expected { return suspendCancellableCoroutine { continuation -> this.setNavigationRouteLines( newRoutes, + activeLegIndex, alternativeRoutesMetadata ) { value -> continuation.resume(value) } @@ -123,6 +165,46 @@ object MapboxRouteLineApiExtensions { * * @param newRoutes one or more routes. The first route in the collection will be considered * the primary route and any additional routes will be alternate routes. + * @param activeLegIndex the index of the currently active leg of the primary route. + * This is used when [MapboxRouteLineOptions.styleInactiveRouteLegsIndependently] is enabled. + * + * @return a state which contains the side effects to be applied to the map + */ + suspend fun MapboxRouteLineApi.setNavigationRoutes( + newRoutes: List, + activeLegIndex: Int, + ): Expected { + return setNavigationRoutes( + newRoutes = newRoutes, + activeLegIndex = activeLegIndex, + alternativeRoutesMetadata = emptyList() + ) + } + + /** + * Sets the routes that will be operated on. + * + * @param newRoutes one or more routes. The first route in the collection will be considered + * the primary route and any additional routes will be alternate routes. + * @param alternativeRoutesMetadata if available, the update will hide the portions of the alternative routes + * until the deviation point with the primary route. See [MapboxNavigation.getAlternativeMetadataFor]. + * + * @return a state which contains the side effects to be applied to the map + */ + suspend fun MapboxRouteLineApi.setNavigationRoutes( + newRoutes: List, + alternativeRoutesMetadata: List + ): Expected { + return setNavigationRoutes(newRoutes, 0, alternativeRoutesMetadata) + } + + /** + * Sets the routes that will be operated on. + * + * @param newRoutes one or more routes. The first route in the collection will be considered + * the primary route and any additional routes will be alternate routes. + * @param activeLegIndex the index of the currently active leg of the primary route. + * This is used when [MapboxRouteLineOptions.styleInactiveRouteLegsIndependently] is enabled. * @param alternativeRoutesMetadata if available, the update will hide the portions of the alternative routes * until the deviation point with the primary route. See [MapboxNavigation.getAlternativeMetadataFor]. * @@ -130,11 +212,13 @@ object MapboxRouteLineApiExtensions { */ suspend fun MapboxRouteLineApi.setNavigationRoutes( newRoutes: List, + activeLegIndex: Int, alternativeRoutesMetadata: List ): Expected { return suspendCancellableCoroutine { continuation -> this.setNavigationRoutes( newRoutes, + activeLegIndex, alternativeRoutesMetadata ) { value -> continuation.resume(value) } diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt index 337ba5d45e1..1d277399a66 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt @@ -60,6 +60,7 @@ import com.mapbox.navigation.utils.internal.parallelMap import com.mapbox.turf.TurfConstants import com.mapbox.turf.TurfException import com.mapbox.turf.TurfMisc +import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.cancelChildren @@ -316,9 +317,30 @@ class MapboxRouteLineApi( fun setNavigationRoutes( newRoutes: List, consumer: MapboxNavigationConsumer> + ) { + setNavigationRoutes(newRoutes, 0, consumer) + } + + /** + * Sets the routes that will be operated on. + * + * This can be a long running task with long routes. + * There is a cancel method which will cancel the background tasks. + * + * @param newRoutes one or more routes. The first route in the collection will be considered + * the primary route and any additional routes will be alternate routes. + * @param activeLegIndex the index of the currently active leg of the primary route. + * This is used when [MapboxRouteLineOptions.styleInactiveRouteLegsIndependently] is enabled. + * @param consumer a method that consumes the result of the operation. + */ + fun setNavigationRoutes( + newRoutes: List, + activeLegIndex: Int, + consumer: MapboxNavigationConsumer> ) { setNavigationRoutes( newRoutes = newRoutes, + activeLegIndex = activeLegIndex, alternativeRoutesMetadata = emptyList(), consumer = consumer ) @@ -340,11 +362,34 @@ class MapboxRouteLineApi( newRoutes: List, alternativeRoutesMetadata: List, consumer: MapboxNavigationConsumer> + ) { + setNavigationRoutes(newRoutes, 0, alternativeRoutesMetadata, consumer) + } + + /** + * Sets the routes that will be operated on. + * + * This can be a long running task with long routes. + * There is a cancel method which will cancel the background tasks. + * + * @param newRoutes one or more routes. The first route in the collection will be considered + * the primary route and any additional routes will be alternate routes. + * @param activeLegIndex the index of the currently active leg of the primary route. + * This is used when [MapboxRouteLineOptions.styleInactiveRouteLegsIndependently] is enabled. + * @param alternativeRoutesMetadata if available, the update will hide the portions of the alternative routes + * until the deviation point with the primary route. See [MapboxNavigation.getAlternativeMetadataFor]. + * @param consumer a method that consumes the result of the operation. + */ + fun setNavigationRoutes( + newRoutes: List, + activeLegIndex: Int, + alternativeRoutesMetadata: List, + consumer: MapboxNavigationConsumer> ) { val routeLines = newRoutes.map { NavigationRouteLine(it, null) } - setNavigationRouteLines(routeLines, alternativeRoutesMetadata, consumer) + setNavigationRouteLines(routeLines, activeLegIndex, alternativeRoutesMetadata, consumer) } /** @@ -384,6 +429,29 @@ class MapboxRouteLineApi( newRoutes: List, alternativeRoutesMetadata: List, consumer: MapboxNavigationConsumer> + ) { + setNavigationRouteLines(newRoutes, 0, alternativeRoutesMetadata, consumer) + } + + /** + * Sets the routes that will be operated on. + * + * This can be a long running task with long routes. + * There is a cancel method which will cancel the background tasks. + * + * @param newRoutes one or more routes. The first route in the collection will be considered + * the primary route and any additional routes will be alternate routes. + * @param activeLegIndex the index of the currently active leg of the primary route. + * This is used when [MapboxRouteLineOptions.styleInactiveRouteLegsIndependently] is enabled. + * @param alternativeRoutesMetadata if available, the update will hide the portions of the alternative routes + * until the deviation point with the primary route. See [MapboxNavigation.getAlternativeMetadataFor]. + * @param consumer a method that consumes the result of the operation. + */ + fun setNavigationRouteLines( + newRoutes: List, + activeLegIndex: Int, + alternativeRoutesMetadata: List, + consumer: MapboxNavigationConsumer> ) { cancel() jobControl.scope.launch(Dispatchers.Main) { @@ -393,7 +461,8 @@ class MapboxRouteLineApi( val routeData = setNewRouteData( newRoutes.map(NavigationRouteLine::route), featureDataProvider, - alternativeRoutesMetadata + alternativeRoutesMetadata, + activeLegIndex ) consumer.accept(routeData) } @@ -413,7 +482,7 @@ class MapboxRouteLineApi( mutex.withLock { val featureDataProvider: () -> List = MapboxRouteLineUtils.getRouteFeatureDataProvider(routes) - val result = buildDrawRoutesState(featureDataProvider) + val result = buildDrawRoutesState(featureDataProvider, activeLegIndex) consumer.accept(result) } } @@ -1140,7 +1209,8 @@ class MapboxRouteLineApi( private suspend fun setNewRouteData( newRoutes: List, featureDataProvider: () -> List, - alternativeRoutesMetadata: List + alternativeRoutesMetadata: List, + activeLegIndex: Int, ): Expected { ifNonNull(newRoutes.firstOrNull()) { primaryRouteCandidate -> if (!primaryRouteCandidate.directionsRoute.isSameRoute(primaryRoute?.directionsRoute)) { @@ -1152,15 +1222,17 @@ class MapboxRouteLineApi( routes.clear() routes.addAll(newRoutes) primaryRoute = newRoutes.firstOrNull() + this.activeLegIndex = INVALID_ACTIVE_LEG_INDEX resetCaches() alternativesDeviationOffset = MapboxRouteLineUtils.getAlternativeRoutesDeviationOffsets(alternativeRoutesMetadata) - return buildDrawRoutesState(featureDataProvider) + return buildDrawRoutesState(featureDataProvider, activeLegIndex) } private suspend fun buildDrawRoutesState( - featureDataProvider: () -> List + featureDataProvider: () -> List, + legIndex: Int ): Expected { val routeFeatureDataDef = jobControl.scope.async { featureDataProvider() @@ -1181,61 +1253,125 @@ class MapboxRouteLineApi( it.route == routes.first() } val vanishingPointOffset = routeLineOptions.vanishingRouteLine?.vanishPointOffset ?: 0.0 + val routeLineColorResources = routeLineOptions.resourceProvider.routeLineColorResources val primaryRouteTrafficLineExpressionDef = jobControl.scope.async { partitionedRoutes.first.firstOrNull()?.route?.run { - MapboxRouteLineUtils.getTrafficLineExpressionProducer( - this.directionsRoute, - routeLineOptions.resourceProvider.routeLineColorResources, - trafficBackfillRoadClasses, - true, + val workingRouteLineExpressionData = + MapboxRouteLineUtils.calculateRouteLineSegments( + this.directionsRoute, + trafficBackfillRoadClasses, + isPrimaryRoute = true, + routeLineColorResources, + ).run { + if (routeLineOptions.styleInactiveRouteLegsIndependently) { + alternativelyStyleSegmentsNotInLeg( + legIndex, + this, + ) + } else { + this + } + } + + MapboxRouteLineUtils.getTrafficLineExpression( vanishingPointOffset, Color.TRANSPARENT, - routeLineOptions.resourceProvider.routeLineColorResources - .routeUnknownCongestionColor, + routeLineColorResources.routeUnknownCongestionColor, + routeLineOptions.softGradientTransition / directionsRoute.distance(), routeLineOptions.displaySoftGradientForTraffic, - routeLineOptions.softGradientTransition + workingRouteLineExpressionData ) - }?.generateExpression() + } + } + + // The RouteLineExpressionData is only needed if the vanishing route line feature + // or styleInactiveRouteLegsIndependently feature are enabled. + val segmentsDef: Deferred>? = if ( + routeLineOptions.vanishingRouteLine != null || + routeLineOptions.styleInactiveRouteLegsIndependently + ) { + jobControl.scope.async { + partitionedRoutes.first.firstOrNull()?.route?.run { + MapboxRouteLineUtils.calculateRouteLineSegments( + this.directionsRoute, + trafficBackfillRoadClasses, + true, + routeLineColorResources + ) + } ?: listOf() + } + } else { + null + } + // If the route has multiple legs the route line expression data is needed immediately + // to draw the independently styled legs correctly. If not the calculation can be deferred. + segmentsDef?.let { deferred -> + val legsCount = partitionedRoutes.first.firstOrNull() + ?.route?.directionsRoute?.legs()?.size ?: 0 + when (legsCount > 1) { + true -> { + routeLineExpressionData = deferred.await() + } + + false -> { + jobControl.scope.launch(Dispatchers.Main) { + routeLineExpressionData = deferred.await() + } + } + } } val primaryRouteBaseExpressionDef = jobControl.scope.async { - MapboxRouteLineUtils.getRouteLineExpression( - vanishingPointOffset, - routeLineOptions.resourceProvider.routeLineColorResources.routeLineTraveledColor, - routeLineOptions.resourceProvider.routeLineColorResources.routeDefaultColor - ) + if (routeLineOptions.styleInactiveRouteLegsIndependently) { + MapboxRouteLineUtils.getRouteLineExpression( + vanishingPointOffset, + routeLineExpressionData, + routeLineColorResources.routeLineTraveledColor, + routeLineColorResources.routeDefaultColor, + routeLineColorResources.inActiveRouteLegsColor, + legIndex, + ) + } else { + MapboxRouteLineUtils.getRouteLineExpression( + vanishingPointOffset, + routeLineColorResources.routeLineTraveledColor, + routeLineColorResources.routeDefaultColor + ) + } } val primaryRouteCasingExpressionDef = jobControl.scope.async { - MapboxRouteLineUtils.getRouteLineExpression( - vanishingPointOffset, - routeLineOptions - .resourceProvider - .routeLineColorResources - .routeLineTraveledCasingColor, - routeLineOptions.resourceProvider.routeLineColorResources.routeCasingColor - ) + if (routeLineOptions.styleInactiveRouteLegsIndependently) { + MapboxRouteLineUtils.getRouteLineExpression( + vanishingPointOffset, + routeLineExpressionData, + routeLineColorResources.routeLineTraveledCasingColor, + routeLineColorResources.routeCasingColor, + Color.TRANSPARENT, + legIndex + ) + } else { + MapboxRouteLineUtils.getRouteLineExpression( + vanishingPointOffset, + routeLineColorResources.routeLineTraveledCasingColor, + routeLineColorResources.routeCasingColor, + ) + } } val primaryRouteTrailExpressionDef = jobControl.scope.async { MapboxRouteLineUtils.getRouteLineExpression( vanishingPointOffset, - routeLineOptions.resourceProvider.routeLineColorResources.routeLineTraveledColor, - routeLineOptions.resourceProvider.routeLineColorResources.routeLineTraveledColor + routeLineColorResources.routeLineTraveledColor, + routeLineColorResources.routeLineTraveledColor ) } val primaryRouteTrailCasingExpressionDef = jobControl.scope.async { MapboxRouteLineUtils.getRouteLineExpression( vanishingPointOffset, - routeLineOptions - .resourceProvider - .routeLineColorResources - .routeLineTraveledCasingColor, - routeLineOptions - .resourceProvider - .routeLineColorResources - .routeLineTraveledCasingColor + routeLineColorResources.routeLineTraveledCasingColor, + routeLineColorResources.routeLineTraveledCasingColor ) } @@ -1246,8 +1382,8 @@ class MapboxRouteLineApi( val alternateRoute1LineColors = getMatchingColors( partitionedRoutes.second.firstOrNull()?.featureCollection, routeLineOptions.routeStyleDescriptors, - routeLineOptions.resourceProvider.routeLineColorResources.alternativeRouteDefaultColor, - routeLineOptions.resourceProvider.routeLineColorResources.alternativeRouteCasingColor + routeLineColorResources.alternativeRouteDefaultColor, + routeLineColorResources.alternativeRouteCasingColor ) val alternateRoute1BaseExpressionDef = jobControl.scope.async { @@ -1297,8 +1433,8 @@ class MapboxRouteLineApi( val alternateRoute2LineColors = getMatchingColors( partitionedRoutes.second.getOrNull(1)?.featureCollection, routeLineOptions.routeStyleDescriptors, - routeLineOptions.resourceProvider.routeLineColorResources.alternativeRouteDefaultColor, - routeLineOptions.resourceProvider.routeLineColorResources.alternativeRouteCasingColor + routeLineColorResources.alternativeRouteDefaultColor, + routeLineColorResources.alternativeRouteCasingColor ) val alternateRoute2BaseExpressionDef = jobControl.scope.async { @@ -1345,15 +1481,12 @@ class MapboxRouteLineApi( partitionedRoutes.second.firstOrNull()?.route?.run { MapboxRouteLineUtils.getTrafficLineExpressionProducer( this.directionsRoute, - routeLineOptions.resourceProvider.routeLineColorResources, + routeLineColorResources, trafficBackfillRoadClasses, false, alternativesDeviationOffset[this.id] ?: 0.0, Color.TRANSPARENT, - routeLineOptions - .resourceProvider - .routeLineColorResources - .alternativeRouteUnknownCongestionColor, + routeLineColorResources.alternativeRouteUnknownCongestionColor, routeLineOptions.displaySoftGradientForTraffic, routeLineOptions.softGradientTransition ) @@ -1364,15 +1497,12 @@ class MapboxRouteLineApi( if (partitionedRoutes.second.size > 1) { MapboxRouteLineUtils.getTrafficLineExpressionProducer( partitionedRoutes.second[1].route.directionsRoute, - routeLineOptions.resourceProvider.routeLineColorResources, + routeLineColorResources, trafficBackfillRoadClasses, false, alternativesDeviationOffset[partitionedRoutes.second[1].route.id] ?: 0.0, Color.TRANSPARENT, - routeLineOptions - .resourceProvider - .routeLineColorResources - .alternativeRouteUnknownCongestionColor, + routeLineColorResources.alternativeRouteUnknownCongestionColor, routeLineOptions.displaySoftGradientForTraffic, routeLineOptions.softGradientTransition ).generateExpression() @@ -1390,15 +1520,14 @@ class MapboxRouteLineApi( MapboxRouteLineUtils.getRestrictedLineExpressionProducer( this.directionsRoute, 0.0, - 0, - routeLineOptions.resourceProvider.routeLineColorResources + legIndex, + routeLineColorResources ) } else { MapboxRouteLineUtils.getDisabledRestrictedLineExpressionProducer( 0.0, - activeLegIndex, - routeLineOptions.resourceProvider.routeLineColorResources - .restrictedRoadColor + legIndex, + routeLineColorResources.restrictedRoadColor ) } }?.generateExpression() @@ -1437,27 +1566,6 @@ class MapboxRouteLineApi( } } - // The RouteLineExpressionData is only needed if the vanishing route line feature - // or styleInactiveRouteLegsIndependently feature are enabled. - if ( - routeLineOptions.vanishingRouteLine != null || - routeLineOptions.styleInactiveRouteLegsIndependently - ) { - jobControl.scope.launch(Dispatchers.Main) { - val segmentsDef = jobControl.scope.async { - partitionedRoutes.first.firstOrNull()?.route?.run { - MapboxRouteLineUtils.calculateRouteLineSegments( - this.directionsRoute, - trafficBackfillRoadClasses, - true, - routeLineOptions.resourceProvider.routeLineColorResources - ) - } ?: listOf() - } - routeLineExpressionData = segmentsDef.await() - } - } - // This call is resource intensive so it needs to come last so that // it doesn't consume resources used by the calculations above. The results // of this call aren't necessary to return to the caller but the calculations above are. diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt index c59f4764e85..8cc5c81720e 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt @@ -214,29 +214,17 @@ internal class VanishingRouteLine { ) { granularDistances, index -> ifNonNull(getOffset(point, granularDistances, index)) { offset -> vanishPointOffset = offset - val trafficLineExpressionProvider = if (useSoftGradient) { - { - MapboxRouteLineUtils.getTrafficLineExpressionSoftGradient( - offset, - routeResourceProvider.routeLineColorResources.routeLineTraveledColor, - routeResourceProvider - .routeLineColorResources - .routeUnknownCongestionColor, - softGradientTransition, - routeLineExpressionData - ) - } - } else { - { - MapboxRouteLineUtils.getTrafficLineExpression( - offset, - routeResourceProvider.routeLineColorResources.routeLineTraveledColor, - routeResourceProvider - .routeLineColorResources - .routeUnknownCongestionColor, - routeLineExpressionData - ) - } + val trafficLineExpressionProvider = { + MapboxRouteLineUtils.getTrafficLineExpression( + offset, + routeResourceProvider.routeLineColorResources.routeLineTraveledColor, + routeResourceProvider + .routeLineColorResources + .routeUnknownCongestionColor, + softGradientTransition, + useSoftGradient, + routeLineExpressionData + ) } val routeLineExpressionProvider = { MapboxRouteLineUtils.getRouteLineExpression( diff --git a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt index 541a869e089..4fc37ddc611 100644 --- a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt +++ b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt @@ -51,6 +51,7 @@ import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.WAYPOINT_LAYER_ID import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.WAYPOINT_SOURCE_ID import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineOptions import com.mapbox.navigation.ui.maps.route.line.model.RouteLineColorResources +import com.mapbox.navigation.ui.maps.route.line.model.RouteLineExpressionData import com.mapbox.navigation.ui.maps.testing.TestingUtil.loadRoute import io.mockk.every import io.mockk.mockk @@ -60,6 +61,7 @@ import io.mockk.verify import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Before +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @@ -611,6 +613,213 @@ class MapboxRouteLineUtilsRoboTest { ) } + @Test + fun getTrafficLineExpression() { + val routeLineColorResources = RouteLineColorResources.Builder().build() + val expectedPrimaryTrafficLineExpression = "[step, [line-progress], " + + "[rgba, 0.0, 0.0, 0.0, 0.0], 0.0, [rgba, 86.0, 168.0, 251.0, 1.0], " + + "0.9425498931842539, [rgba, 255.0, 149.0, 0.0, 1.0], 1.0, " + + "[rgba, 86.0, 168.0, 251.0, 1.0]]" + + val result = MapboxRouteLineUtils.getTrafficLineExpression( + 0.0, + Color.TRANSPARENT, + routeLineColorResources.routeUnknownCongestionColor, + 0.0, + false, + listOf( + RouteLineExpressionData(0.0, routeLineColorResources.routeLowCongestionColor, 0), + RouteLineExpressionData( + offset = 0.9425498931842539, + segmentColor = routeLineColorResources.routeModerateCongestionColor, + legIndex = 0 + ), + RouteLineExpressionData(1.0, routeLineColorResources.routeLowCongestionColor, 0), + ) + ) + + assertEquals( + expectedPrimaryTrafficLineExpression, + result.toString() + ) + } + + @Test + fun `getTrafficLineExpression when duplicate point`() { + val routeLineColorResources = RouteLineColorResources.Builder().build() + val expectedPrimaryTrafficLineExpression = "[step, [line-progress], " + + "[rgba, 0.0, 0.0, 0.0, 0.0], 0.0, " + + "[rgba, 86.0, 168.0, 251.0, 1.0], 0.10373821458415478, " + + "[rgba, 255.0, 149.0, 0.0, 1.0], 0.1240124365711821, " + + "[rgba, 86.0, 168.0, 251.0, 1.0], 0.2718982903427929, " + + "[rgba, 255.0, 149.0, 0.0, 1.0], 0.32264099467350016, " + + "[rgba, 86.0, 168.0, 251.0, 1.0], 0.4897719974699625, " + + // this is the moderate color at the start of the second leg + // even though it's preceded by a duplicate 'severe' point which is ignored + "[rgba, 255.0, 149.0, 0.0, 1.0], 0.5421388243827154, " + + "[rgba, 86.0, 168.0, 251.0, 1.0], 0.5710651139490561, " + + "[rgba, 255.0, 149.0, 0.0, 1.0], 0.5916095976376619, " + + "[rgba, 86.0, 168.0, 251.0, 1.0], 0.88674421638117, " + + "[rgba, 255.0, 149.0, 0.0, 1.0], 0.9423002251348892, " + + "[rgba, 86.0, 168.0, 251.0, 1.0]]" + + val result = MapboxRouteLineUtils.getTrafficLineExpression( + vanishingPointOffset = 0.0, + lineStartColor = Color.TRANSPARENT, + lineColor = routeLineColorResources.routeUnknownCongestionColor, + stopGap = 0.0, + useSoftGradient = false, + segments = listOf( + RouteLineExpressionData(0.0, routeLineColorResources.routeLowCongestionColor, 0), + RouteLineExpressionData( + 0.10373821458415478, + routeLineColorResources.routeModerateCongestionColor, + 0 + ), + RouteLineExpressionData( + 0.1240124365711821, + routeLineColorResources.routeLowCongestionColor, + 0 + ), + RouteLineExpressionData( + 0.2718982903427929, + routeLineColorResources.routeModerateCongestionColor, + 0 + ), + RouteLineExpressionData( + 0.32264099467350016, + routeLineColorResources.routeLowCongestionColor, + 0 + ), + + RouteLineExpressionData( + 0.4897719974699625, + routeLineColorResources.routeModerateCongestionColor, + 1 + ), + RouteLineExpressionData( + 0.5421388243827154, + routeLineColorResources.routeLowCongestionColor, + 1 + ), + RouteLineExpressionData( + 0.5710651139490561, + routeLineColorResources.routeModerateCongestionColor, + 1 + ), + RouteLineExpressionData( + 0.5916095976376619, + routeLineColorResources.routeLowCongestionColor, + 1 + ), + RouteLineExpressionData( + 0.88674421638117, + routeLineColorResources.routeModerateCongestionColor, + 1 + ), + RouteLineExpressionData( + 0.9423002251348892, + routeLineColorResources.routeLowCongestionColor, + 1 + ), + ) + ) + + assertEquals( + expectedPrimaryTrafficLineExpression, + result.toString() + ) + } + + @Test + @Ignore( + "This cherry-picked test fails because we used to take the first duplicate offset " + + "instead of the last, which was fixed in " + + "https://github.com/mapbox/mapbox-navigation-android/pull/6440" + ) + fun `getTrafficLineExpression with classes override when duplicate point`() { + val colorResources = RouteLineColorResources.Builder() + .routeUnknownCongestionColor(-9) + .routeLowCongestionColor(-1) + .routeCasingColor(33) + .routeDefaultColor(33) + .routeHeavyCongestionColor(33) + .routeLineTraveledCasingColor(33) + .routeLineTraveledColor(33) + .routeModerateCongestionColor(33) + .routeSevereCongestionColor(33) + .build() + val expectedPrimaryTrafficLineExpression = "[step, [line-progress], " + + "[rgba, 0.0, 0.0, 0.0, 0.0], 0.0, " + + "[rgba, 255.0, 255.0, 247.0, 1.0], 0.5688813850361385, " + + "[rgba, 255.0, 255.0, 255.0, 1.0], 1.0, " + + "[rgba, 255.0, 255.0, 247.0, 1.0]]" + + val result = MapboxRouteLineUtils.getTrafficLineExpression( + vanishingPointOffset = 0.0, + lineStartColor = Color.TRANSPARENT, + lineColor = colorResources.routeUnknownCongestionColor, + stopGap = 0.0, + useSoftGradient = false, + segments = listOf( + RouteLineExpressionData(0.0, colorResources.routeLowCongestionColor, 0), + RouteLineExpressionData( + offset = 0.5688813850361385, + segmentColor = colorResources.routeUnknownCongestionColor, + legIndex = 0 + ), + RouteLineExpressionData( + offset = 0.5688813850361385, + segmentColor = colorResources.routeLowCongestionColor, + legIndex = 0 + ), + RouteLineExpressionData(1.0, colorResources.routeUnknownCongestionColor, 0), + ) + ) + + assertEquals( + expectedPrimaryTrafficLineExpression, + result.toString() + ) + } + + @Test + fun getTrafficLineExpression_whenUseSoftGradient() { + val routeLineColorResources = RouteLineColorResources.Builder().build() + val expectedPrimaryTrafficLineExpression = "[interpolate, [linear], [line-progress], " + + "0.0, [rgba, 86.0, 168.0, 251.0, 1.0], " + + "0.6934838906942539, [rgba, 86.0, 168.0, 251.0, 1.0], " + + "0.9425498931842539, [rgba, 255.0, 149.0, 0.0, 1.0], " + + "0.9425498931942539, [rgba, 255.0, 149.0, 0.0, 1.0], " + + "1.0, [rgba, 86.0, 168.0, 251.0, 1.0]]" + + val result = MapboxRouteLineUtils.getTrafficLineExpression( + 0.0, + Color.TRANSPARENT, + routeLineColorResources.routeUnknownCongestionColor, + 0.24906600249, + true, + listOf( + RouteLineExpressionData(0.0, routeLineColorResources.routeLowCongestionColor, 0), + RouteLineExpressionData( + 0.9425498931842539, + routeLineColorResources.routeModerateCongestionColor, + 0 + ), + RouteLineExpressionData( + 1.0, + routeLineColorResources.routeLowCongestionColor, + 0 + ), + ) + ) + + assertEquals( + expectedPrimaryTrafficLineExpression, + result.toString() + ) + } + @Test fun getRouteLineExpression() { val expectedExpression = "[step, [line-progress], [rgba, 255.0, 0.0, 0.0, 1.0], 0.2," + diff --git a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/ui/RouteLineComponentTest.kt b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/ui/RouteLineComponentTest.kt index 66e4d662cca..b3ff78257a7 100644 --- a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/ui/RouteLineComponentTest.kt +++ b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/ui/RouteLineComponentTest.kt @@ -208,7 +208,14 @@ class RouteLineComponentTest { routesObserverSlot.captured.onRoutesChanged(routesUpdateResult) - verify { mockApi.setNavigationRouteLines(any(), any(), capture(callbackSlot)) } + verify { + mockApi.setNavigationRouteLines( + any(), + 0, + any(), + capture(callbackSlot) + ) + } callbackSlot.captured.accept(expectedMockError) verify { mockView.renderRouteDrawData(mockStyle, expectedMockError) } } @@ -240,7 +247,14 @@ class RouteLineComponentTest { routesObserverSlot.captured.onRoutesChanged(routesUpdateResult) - verify { mockApi.setNavigationRouteLines(any(), any(), capture(callbackSlot)) } + verify { + mockApi.setNavigationRouteLines( + any(), + 0, + any(), + capture(callbackSlot) + ) + } callbackSlot.captured.accept(expectedMockError) verify { mockView.renderRouteDrawData(mockStyle, expectedMockError) } } @@ -272,7 +286,14 @@ class RouteLineComponentTest { routesObserverSlot.captured.onRoutesChanged(routesUpdateResult) - verify { mockApi.setNavigationRouteLines(any(), any(), capture(callbackSlot)) } + verify { + mockApi.setNavigationRouteLines( + any(), + 0, + any(), + capture(callbackSlot) + ) + } callbackSlot.captured.accept(expectedMockError) verify { mockView.renderRouteDrawData(mockStyle, expectedMockError) } } @@ -304,7 +325,14 @@ class RouteLineComponentTest { routesObserverSlot.captured.onRoutesChanged(routesUpdateResult) - verify { mockApi.setNavigationRouteLines(any(), any(), capture(callbackSlot)) } + verify { + mockApi.setNavigationRouteLines( + any(), + 0, + any(), + capture(callbackSlot) + ) + } callbackSlot.captured.accept(expectedMockError) verify { mockView.renderRouteDrawData(mockStyle, expectedMockError) } } diff --git a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiRoboTest.kt b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiRoboTest.kt index 8eff5cd5d83..ab7e545f083 100644 --- a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiRoboTest.kt +++ b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiRoboTest.kt @@ -4,12 +4,16 @@ import android.content.Context import android.graphics.Color import androidx.test.core.app.ApplicationProvider import com.mapbox.api.directions.v5.models.DirectionsResponse +import com.mapbox.bindgen.Expected import com.mapbox.bindgen.ExpectedFactory import com.mapbox.core.constants.Constants import com.mapbox.geojson.LineString import com.mapbox.geojson.utils.PolylineUtils +import com.mapbox.maps.extension.style.expressions.generated.Expression import com.mapbox.navigation.base.internal.NativeRouteParserWrapper import com.mapbox.navigation.base.route.NavigationRoute +import com.mapbox.navigation.base.route.RouterOrigin +import com.mapbox.navigation.base.route.toNavigationRoute import com.mapbox.navigation.base.trip.model.RouteProgress import com.mapbox.navigation.base.trip.model.RouteProgressState import com.mapbox.navigation.core.routealternatives.AlternativeRouteMetadata @@ -23,7 +27,9 @@ import com.mapbox.navigation.ui.maps.route.line.MapboxRouteLineApiExtensions.sho import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineOptions import com.mapbox.navigation.ui.maps.route.line.model.RouteLine import com.mapbox.navigation.ui.maps.route.line.model.RouteLineColorResources +import com.mapbox.navigation.ui.maps.route.line.model.RouteLineError import com.mapbox.navigation.ui.maps.route.line.model.RouteLineResources +import com.mapbox.navigation.ui.maps.route.line.model.RouteSetValue import com.mapbox.navigation.ui.maps.testing.TestingUtil.loadRoute import com.mapbox.navigation.utils.internal.InternalJobControlFactory import com.mapbox.navigation.utils.internal.JobControl @@ -40,6 +46,7 @@ import kotlinx.coroutines.delay import org.json.JSONObject import org.junit.After import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotEquals import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Before @@ -159,6 +166,119 @@ class MapboxRouteLineApiRoboTest { ) } + @Test + fun `setNavigationRoutes takes into account inactiveLegStyling and legIndex`() = + coroutineRule.runBlockingTest { + val route = loadRoute("multileg_route.json").toNavigationRoute(RouterOrigin.Custom()) + val altRoute = loadRoute("multileg_route_with_overlap.json") + .toNavigationRoute(RouterOrigin.Custom()) + + val apiWithIndependentInactiveStylingEnabled = MapboxRouteLineApi( + MapboxRouteLineOptions.Builder(ctx) + .styleInactiveRouteLegsIndependently(true) + .build() + ) + val apiWithIndependentInactiveStylingDisabled = MapboxRouteLineApi( + MapboxRouteLineOptions.Builder(ctx) + .build() + ) + + val independentStylingEnabledLegZeroResult = apiWithIndependentInactiveStylingEnabled + .setNavigationRoutes(listOf(route, altRoute)) + val independentStylingEnabledLegOneResult = apiWithIndependentInactiveStylingEnabled + .setNavigationRoutes(listOf(route, altRoute), activeLegIndex = 1) + val independentStylingDisabledLegZeroResult = apiWithIndependentInactiveStylingDisabled + .setNavigationRoutes(listOf(route, altRoute)) + val independentStylingDisabledLegOneResult = apiWithIndependentInactiveStylingDisabled + .setNavigationRoutes(listOf(route, altRoute), activeLegIndex = 1) + + val differentValuesToCheck = listOf( + independentStylingEnabledLegZeroResult, + independentStylingEnabledLegOneResult, + independentStylingDisabledLegZeroResult, + ) + val equalValuesToCheck = listOf( + independentStylingDisabledLegZeroResult, + independentStylingDisabledLegOneResult, + ) + val allValuesToCheck = (differentValuesToCheck + equalValuesToCheck).toSet() + checkNotEquals(differentValuesToCheck) { + it.primaryRouteLineData.dynamicData.trafficExpressionProvider!!.generateExpression() + } + checkEquals(equalValuesToCheck) { + it.primaryRouteLineData.dynamicData.trafficExpressionProvider!!.generateExpression() + } + println("failing") + checkNotEquals(differentValuesToCheck) { + it.primaryRouteLineData.dynamicData.baseExpressionProvider.generateExpression() + } + checkEquals(equalValuesToCheck) { + it.primaryRouteLineData.dynamicData.baseExpressionProvider.generateExpression() + } + checkNotEquals(differentValuesToCheck) { + it.primaryRouteLineData.dynamicData.casingExpressionProvider.generateExpression() + } + checkEquals(equalValuesToCheck) { + it.primaryRouteLineData.dynamicData.casingExpressionProvider.generateExpression() + } + checkEquals(allValuesToCheck) { + it.primaryRouteLineData.dynamicData.trailExpressionProvider!!.generateExpression() + } + checkEquals(allValuesToCheck) { + it.primaryRouteLineData.dynamicData.trailCasingExpressionProvider!! + .generateExpression() + } + + checkEquals(allValuesToCheck) { + it.alternativeRouteLinesData.first().dynamicData.trafficExpressionProvider!! + .generateExpression() + } + checkEquals(allValuesToCheck) { + it.alternativeRouteLinesData.first().dynamicData.baseExpressionProvider + .generateExpression() + } + checkEquals(allValuesToCheck) { + it.alternativeRouteLinesData.first().dynamicData.casingExpressionProvider + .generateExpression() + } + checkEquals(allValuesToCheck) { + it.alternativeRouteLinesData.first().dynamicData.trailExpressionProvider!! + .generateExpression() + } + checkEquals(allValuesToCheck) { + it.alternativeRouteLinesData.first().dynamicData.trailCasingExpressionProvider!! + .generateExpression() + } + } + + private fun checkNotEquals( + values: Iterable>, + expressionExtractor: (RouteSetValue) -> Expression + ) { + val expressions = values.map { expressionExtractor(it.value!!) } + expressions.forEachIndexed { index, expression -> + println("$index; $expression") + } + for (i in 0 until expressions.size) { + for (j in i + 1 until expressions.size) { + assertNotEquals(expressions[i], expressions[j]) + } + } + } + + private fun checkEquals( + values: Iterable>, + expressionExtractor: (RouteSetValue) -> Expression + ) { + val expressions = values.map { expressionExtractor(it.value!!) } + if (expressions.isNotEmpty()) { + val first = expressions.first() + expressions.drop(1).forEach { + assertEquals(first, it) + } + } + } + @Test fun setRoutesTrafficExpressionsWithAlternativeRoutes() = coroutineRule.runBlockingTest { val expectedPrimaryTrafficLineExpression = "[step, [line-progress], " + diff --git a/libnavui-maps/src/test/resources/multileg_route_with_overlap.json b/libnavui-maps/src/test/resources/multileg_route_with_overlap.json new file mode 100644 index 00000000000..2cd15510736 --- /dev/null +++ b/libnavui-maps/src/test/resources/multileg_route_with_overlap.json @@ -0,0 +1 @@ +{"country_crossed":false,"weight_typical":117.124,"routeIndex":"0","distance":2326.407,"duration":125.848,"duration_typical":118.234,"geometry":"}f}|uA~b{khFlEkUrH}a@nDiZnDsThCsQdBaNtE_b@xIuy@pNy~A~Dgd@jI{_AjIy_AdFgm@rHqx@fDi`@pGgn@jEy[nDaXpD_WdCeVrDqFjDwJxByJn@qHNgFCiEhAgIhCcHn@{D~AiA\\oA^cAV}CEkBmAyDcA_AgC{@oB^y@t@c@`@_AdCU|CDbANxA}@jJLpE]dI}CtYiCtQk@bLeCdVqD~VoD`XkEx[qGfn@gDh`@sHpx@eFfm@kIx_AkIz_A_Efd@qNx~AyIty@uE~a@eB`NiCrQoDrTyGbXaQ`~@","weight":124.568,"weight_name":"auto","legs":[{"weight_typical":57.966,"weight":61.728,"via_waypoints":[],"distance":1158.042,"duration":62.188,"duration_typical":58.349,"summary":"WA 14 East","admins":[{"iso_3166_1":"US","iso_3166_1_alpha3":"USA"}],"steps":[{"weight_typical":53.24,"distance":1121.76,"duration":56.705,"duration_typical":52.866,"speedLimitUnit":"mph","speedLimitSign":"mutcd","geometry":"}f}|uA~b{khFlEkUrH}a@nDiZnDsThCsQdBaNtE_b@xIuy@pNy~A~Dgd@jI{_AjIy_AdFgm@rHqx@fDi`@pGgn@jEy[nDaXpD_WdCeVrDqFjDwJxByJn@qHNgFCiEhAgIhCcHn@{D","name":"Lewis and Clark Highway","ref":"WA 14 East","mode":"driving","maneuver":{"location":[-122.370112,45.579391],"bearing_before":0.0,"bearing_after":112.0,"instruction":"Drive east on WA 14 East/Lewis and Clark Highway.","type":"depart"},"voiceInstructions":[{"distanceAlongGeometry":1121.76,"announcement":"Drive east on Washington 14 East, Lewis and Clark Highway.","ssmlAnnouncement":"\u003cspeak\u003e\u003camazon:effect name\u003d\"drc\"\u003e\u003cprosody rate\u003d\"1.08\"\u003eDrive east on \u003csay-as interpret-as\u003d\"address\"\u003eWashington 14 East\u003c/say-as\u003e, \u003csay-as interpret-as\u003d\"address\"\u003eLewis and Clark Highway\u003c/say-as\u003e.\u003c/prosody\u003e\u003c/amazon:effect\u003e\u003c/speak\u003e"},{"distanceAlongGeometry":1092.094,"announcement":"In a half mile, Enter the roundabout and take the 3rd exit.","ssmlAnnouncement":"\u003cspeak\u003e\u003camazon:effect name\u003d\"drc\"\u003e\u003cprosody rate\u003d\"1.08\"\u003eIn a half mile, Enter the roundabout and take the 3rd exit.\u003c/prosody\u003e\u003c/amazon:effect\u003e\u003c/speak\u003e"},{"distanceAlongGeometry":180.0,"announcement":"Enter the roundabout and take the 3rd exit.","ssmlAnnouncement":"\u003cspeak\u003e\u003camazon:effect name\u003d\"drc\"\u003e\u003cprosody rate\u003d\"1.08\"\u003eEnter the roundabout and take the 3rd exit.\u003c/prosody\u003e\u003c/amazon:effect\u003e\u003c/speak\u003e"}],"bannerInstructions":[{"distanceAlongGeometry":1121.76,"primary":{"text":"Enter the roundabout and take the 3rd exit","components":[{"text":"Enter the roundabout and take the 3rd exit","type":"text"}],"type":"roundabout","modifier":"right","degrees":173.0,"driving_side":"right"}}],"driving_side":"right","weight":57.003,"intersections":[{"duration":4.597,"weight":4.482,"location":[-122.370112,45.579391],"bearings":[112],"classes":["motorway"],"entry":[true],"out":0,"geometry_index":0,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"motorway"}},{"duration":2.455,"turn_duration":0.009,"weight":2.385,"location":[-122.368758,45.579046],"bearings":[110,286,297],"entry":[true,false,true],"in":1,"out":0,"geometry_index":3,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"trunk"}},{"duration":39,"weight":38.025,"location":[-122.368114,45.578889],"bearings":[107,288],"entry":[true,false],"in":1,"out":0,"geometry_index":5,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"trunk"}},{"turn_weight":1.5,"turn_duration":0.042,"location":[-122.357603,45.577045],"bearings":[101,131,284],"entry":[false,true,false],"in":2,"out":1,"geometry_index":20,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"trunk"}}]},{"weight_typical":4.725,"distance":36.281,"duration":5.483,"duration_typical":5.483,"speedLimitUnit":"mph","speedLimitSign":"mutcd","geometry":"o{w|uAte`khF~AiA\\oA^cAV}CEkBmAyDcA_A","name":"","mode":"driving","maneuver":{"location":[-122.356331,45.576648],"bearing_before":118.0,"bearing_after":152.0,"instruction":"Enter the roundabout and take the 3rd exit.","type":"roundabout","modifier":"slight right","exit":3},"voiceInstructions":[{"distanceAlongGeometry":36.281,"announcement":"You have arrived at your destination.","ssmlAnnouncement":"\u003cspeak\u003e\u003camazon:effect name\u003d\"drc\"\u003e\u003cprosody rate\u003d\"1.08\"\u003eYou have arrived at your destination.\u003c/prosody\u003e\u003c/amazon:effect\u003e\u003c/speak\u003e"}],"bannerInstructions":[{"distanceAlongGeometry":36.281,"primary":{"text":"You have arrived at your destination","components":[{"text":"You have arrived at your destination","type":"text"}],"type":"arrive","modifier":"straight"}}],"driving_side":"right","weight":4.725,"intersections":[{"duration":0.839,"turn_weight":0.75,"turn_duration":0.067,"weight":1.521,"location":[-122.356331,45.576648],"bearings":[21,152,298],"entry":[false,true,false],"in":2,"out":1,"geometry_index":29,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"roundabout"}},{"duration":1.726,"turn_duration":0.349,"weight":1.376,"location":[-122.356294,45.5766],"bearings":[112,175,332],"entry":[true,true,false],"in":2,"out":0,"geometry_index":30,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"roundabout"}},{"duration":0.511,"turn_duration":0.142,"weight":0.369,"location":[-122.356141,45.576557],"bearings":[85,213,292],"entry":[true,false,false],"in":2,"out":0,"geometry_index":33,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"roundabout"}},{"turn_duration":0.949,"location":[-122.356087,45.57656],"bearings":[50,107,265],"entry":[true,true,false],"in":2,"out":0,"geometry_index":34,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"roundabout"}}]},{"weight_typical":0,"distance":0.0,"duration":0.0,"duration_typical":0.0,"speedLimitUnit":"mph","speedLimitSign":"mutcd","geometry":"qzw|uArn_khF??","name":"","mode":"driving","maneuver":{"location":[-122.355962,45.576633],"bearing_before":50.0,"bearing_after":0.0,"instruction":"You have arrived at your destination.","type":"arrive"},"voiceInstructions":[],"bannerInstructions":[],"driving_side":"right","weight":0.0,"intersections":[{"location":[-122.355962,45.576633],"bearings":[230],"entry":[true],"in":0,"geometry_index":36,"admin_index":0}]}],"annotation":{"distance":[30.1,46.8,35.5,28.6,24.5,19.6,45.2,75.7,122.6,47.7,82.9,82.9,59.1,73.8,42.5,60.9,37.6,32.8,31.5,29.9,13.7,17.5,16.2,12.3,9.0,7.9,13.4,13.8,7.8,6.0,3.6,3.2,6.3,4.2,8.4,4.5],"duration":[1.232,1.915,1.45,1.329,1.126,0.906,2.088,3.493,5.662,2.2,3.83,3.827,2.727,3.407,1.966,2.809,1.739,1.512,1.455,1.378,1.35,1.664,1.542,1.162,0.864,0.749,1.277,1.305,0.741,0.839,0.723,0.337,0.666,0.511,1.9,0.508],"speed":[24.4,24.4,24.4,21.7,21.7,21.7,21.7,21.7,21.7,21.7,21.7,21.7,21.7,21.7,21.7,21.7,21.7,21.7,21.7,21.7,10.5,10.5,10.5,10.5,10.5,10.5,10.5,10.5,10.5,7.9,9.5,9.5,9.5,11.4,8.9,8.9],"maxspeed":[{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true}],"congestion_numeric":[0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,19,19,19,19,19,19,19,19,19,null,6,6,6,null,0,0]}},{"weight_typical":59.159,"weight":62.84,"via_waypoints":[],"distance":1168.365,"duration":63.66,"duration_typical":59.885,"summary":"WA 14, WA 14 West","admins":[{"iso_3166_1":"US","iso_3166_1_alpha3":"USA"}],"steps":[{"weight_typical":5.23,"distance":39.447,"duration":6.77,"duration_typical":6.77,"speedLimitUnit":"mph","speedLimitSign":"mutcd","geometry":"qzw|uArn_khFgC{@oB^y@t@c@`@_AdCU|CDbANxA","name":"Lewis and Clark Highway","ref":"WA 14","mode":"driving","maneuver":{"location":[-122.355962,45.576633],"bearing_before":0.0,"bearing_after":4.0,"instruction":"Drive north on WA 14/Lewis and Clark Highway.","type":"depart"},"voiceInstructions":[{"distanceAlongGeometry":39.447,"announcement":"Drive north on Washington 14, Lewis and Clark Highway.","ssmlAnnouncement":"\u003cspeak\u003e\u003camazon:effect name\u003d\"drc\"\u003e\u003cprosody rate\u003d\"1.08\"\u003eDrive north on \u003csay-as interpret-as\u003d\"address\"\u003eWashington 14\u003c/say-as\u003e, \u003csay-as interpret-as\u003d\"address\"\u003eLewis and Clark Highway\u003c/say-as\u003e.\u003c/prosody\u003e\u003c/amazon:effect\u003e\u003c/speak\u003e"},{"distanceAlongGeometry":39.447,"announcement":"Exit the roundabout onto Washington 14 West, Lewis and Clark Highway.","ssmlAnnouncement":"\u003cspeak\u003e\u003camazon:effect name\u003d\"drc\"\u003e\u003cprosody rate\u003d\"1.08\"\u003eExit the roundabout onto \u003csay-as interpret-as\u003d\"address\"\u003eWashington 14 West\u003c/say-as\u003e, \u003csay-as interpret-as\u003d\"address\"\u003eLewis and Clark Highway\u003c/say-as\u003e.\u003c/prosody\u003e\u003c/amazon:effect\u003e\u003c/speak\u003e"}],"bannerInstructions":[{"distanceAlongGeometry":39.447,"primary":{"text":"WA 14 West / Lewis and Clark Highway","components":[{"text":"WA 14","type":"icon","imageBaseURL":"https://api.mapbox.com/public/shields/v4.1/US/wa-14","mapbox_shield":{"base_url":"https://api.mapbox.com/styles/v1","name":"circle-white","text_color":"black","display_ref":"14"}},{"text":"West","type":"text"},{"text":"/","type":"delimiter"},{"text":"Lewis and Clark Highway","type":"text"}],"type":"roundabout","modifier":"right","degrees":186.0,"driving_side":"right"}}],"driving_side":"right","weight":5.23,"intersections":[{"duration":1.579,"weight":1.579,"location":[-122.355962,45.576633],"bearings":[4],"entry":[true],"out":0,"geometry_index":0,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"roundabout"}},{"duration":1.616,"turn_duration":1.016,"weight":0.6,"location":[-122.355948,45.576757],"bearings":[135,184,327],"entry":[false,false,true],"in":1,"out":2,"geometry_index":2,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"roundabout"}},{"duration":2.923,"turn_duration":0.223,"weight":2.7,"location":[-122.355975,45.576786],"bearings":[8,147,293],"entry":[true,false,true],"in":1,"out":2,"geometry_index":3,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"roundabout"}},{"turn_duration":0.301,"location":[-122.356172,45.576844],"bearings":[37,113,256],"entry":[false,false,true],"in":1,"out":2,"geometry_index":7,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"roundabout"}}]},{"weight_typical":53.928,"distance":1128.919,"duration":56.89,"duration_typical":53.114,"speedLimitUnit":"mph","speedLimitSign":"mutcd","geometry":"ggx|uAp~_khF}@jJLpE]dI}CtYiCtQk@bLeCdVqD~VoD`XkEx[qGfn@gDh`@sHpx@eFfm@kIx_AkIz_A_Efd@qNx~AyIty@uE~a@eB`NiCrQoDrTyGbXaQ`~@","name":"Lewis and Clark Highway","ref":"WA 14 West","mode":"driving","maneuver":{"location":[-122.356217,45.576836],"bearing_before":256.0,"bearing_after":277.0,"instruction":"Exit the roundabout onto WA 14 West/Lewis and Clark Highway.","type":"exit roundabout","modifier":"slight right"},"voiceInstructions":[{"distanceAlongGeometry":1098.919,"announcement":"In a half mile, You will arrive at your destination.","ssmlAnnouncement":"\u003cspeak\u003e\u003camazon:effect name\u003d\"drc\"\u003e\u003cprosody rate\u003d\"1.08\"\u003eIn a half mile, You will arrive at your destination.\u003c/prosody\u003e\u003c/amazon:effect\u003e\u003c/speak\u003e"},{"distanceAlongGeometry":123.611,"announcement":"You have arrived at your destination.","ssmlAnnouncement":"\u003cspeak\u003e\u003camazon:effect name\u003d\"drc\"\u003e\u003cprosody rate\u003d\"1.08\"\u003eYou have arrived at your destination.\u003c/prosody\u003e\u003c/amazon:effect\u003e\u003c/speak\u003e"}],"bannerInstructions":[{"distanceAlongGeometry":1128.919,"primary":{"text":"You will arrive at your destination","components":[{"text":"You will arrive at your destination","type":"text"}],"type":"arrive","modifier":"straight"}},{"distanceAlongGeometry":123.611,"primary":{"text":"You have arrived at your destination","components":[{"text":"You have arrived at your destination","type":"text"}],"type":"arrive","modifier":"straight"}}],"driving_side":"right","weight":57.609,"intersections":[{"duration":3.351,"turn_duration":0.028,"weight":3.323,"location":[-122.356217,45.576836],"bearings":[76,206,277],"entry":[false,true,true],"in":0,"out":2,"geometry_index":8,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"trunk"}},{"duration":4.75,"turn_weight":0.5,"turn_duration":0.014,"weight":5.237,"location":[-122.356667,45.576875],"bearings":[77,94,285],"entry":[false,false,true],"in":1,"out":2,"geometry_index":11,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"trunk"}},{"duration":41.117,"turn_duration":0.008,"weight":40.08,"location":[-122.357603,45.577045],"bearings":[102,131,284],"entry":[false,true,true],"in":0,"out":2,"geometry_index":14,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"trunk"}},{"duration":2.578,"weight":2.514,"location":[-122.368114,45.578889],"bearings":[107,288],"entry":[false,true],"in":0,"out":1,"geometry_index":29,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"trunk"}},{"turn_weight":1.5,"turn_duration":0.011,"location":[-122.368758,45.579046],"bearings":[110,286,297],"classes":["motorway"],"entry":[false,false,true],"in":0,"out":2,"geometry_index":31,"is_urban":false,"admin_index":0,"mapbox_streets_v8":{"class":"motorway"}}]},{"weight_typical":0,"distance":0.0,"duration":0.0,"duration_typical":0.0,"speedLimitUnit":"mph","speedLimitSign":"mutcd","geometry":"gl}|uApf{khF??","name":"Lewis and Clark Highway","ref":"WA 14 West","mode":"driving","maneuver":{"location":[-122.370169,45.579476],"bearing_before":292.0,"bearing_after":0.0,"instruction":"You have arrived at your destination.","type":"arrive"},"voiceInstructions":[],"bannerInstructions":[],"driving_side":"right","weight":0.0,"intersections":[{"location":[-122.370169,45.579476],"bearings":[112],"entry":[true],"in":0,"geometry_index":33,"admin_index":0}]}],"annotation":{"distance":[8.0,6.3,3.9,2.4,6.3,6.3,2.7,3.6,14.6,8.2,12.8,34.4,24.6,16.5,29.9,31.5,32.7,37.7,60.8,42.6,73.8,59.1,82.8,83.0,47.7,122.6,75.6,45.3,19.6,24.4,28.7,35.0,85.0],"duration":[0.878,0.702,1.616,0.59,0.966,0.959,0.408,0.652,1.39,0.767,1.195,2.173,1.539,1.038,1.461,1.534,1.594,1.833,2.961,2.072,3.591,2.874,4.034,4.038,2.319,5.968,3.682,2.201,0.955,1.187,1.392,1.495,3.598],"speed":[9.1,9.1,6.4,6.5,6.5,6.5,6.5,10.3,10.7,10.7,10.7,15.9,15.9,15.9,20.5,20.5,20.5,20.5,20.5,20.5,20.5,20.5,20.5,20.5,20.5,20.5,20.5,20.5,20.5,20.6,20.6,23.6,23.6],"maxspeed":[{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"unknown":true},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"},{"speed":89,"unit":"km/h"}],"congestion_numeric":[0,0,null,25,25,25,25,null,0,0,0,0,0,0,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,1,1]}}],"routeOptions":{"baseUrl":"https://api.mapbox.com","user":"mapbox","profile":"driving-traffic","coordinates":"-122.3701121,45.5793898;-122.3559639,45.5766337;-122.3701676,45.5794787","alternatives":true,"language":"en","continue_straight":true,"roundabout_exits":true,"geometries":"polyline6","overview":"full","steps":true,"annotations":"congestion_numeric,maxspeed,closure,speed,duration,distance","voice_instructions":true,"banner_instructions":true,"voice_units":"imperial","enable_refresh":true},"voiceLocale":"en-US","requestUuid":"THHDqFC8RW-5CkHuAinvlpK43QWozH8eBbCjHcI5HfB2svATVOmVHg\u003d\u003d"} \ No newline at end of file diff --git a/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/view/AlternativeRouteActivity.kt b/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/view/AlternativeRouteActivity.kt index 8045b5c3aea..aee3416c88b 100644 --- a/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/view/AlternativeRouteActivity.kt +++ b/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/view/AlternativeRouteActivity.kt @@ -243,7 +243,7 @@ class AlternativeRouteActivity : AppCompatActivity(), OnMapLongClickListener { val updatedRoutes = mutableListOf() updatedRoutes.add(routeProgress.navigationRoute) updatedRoutes.addAll(alternatives) - mapboxNavigation.setNavigationRoutes(updatedRoutes) + mapboxNavigation.setNavigationRoutes(updatedRoutes, mapboxNavigation.currentLegIndex()) } override fun onRouteAlternativesError(error: RouteAlternativesError) {