Skip to content

Commit 060dd38

Browse files
committed
Show alternatives in history replay
1 parent 589c5a4 commit 060dd38

File tree

7 files changed

+156
-7
lines changed

7 files changed

+156
-7
lines changed

examples/src/main/java/com/mapbox/navigation/examples/core/ReplayHistoryActivity.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.mapbox.navigation.base.internal.extensions.applyDefaultParams
2323
import com.mapbox.navigation.base.internal.extensions.coordinates
2424
import com.mapbox.navigation.core.MapboxNavigation
2525
import com.mapbox.navigation.core.directions.session.RoutesRequestCallback
26+
import com.mapbox.navigation.core.fasterroute.FasterRouteObserver
2627
import com.mapbox.navigation.core.replay.MapboxReplayer
2728
import com.mapbox.navigation.core.replay.ReplayLocationEngine
2829
import com.mapbox.navigation.core.replay.history.CustomEventMapper
@@ -171,6 +172,13 @@ class ReplayHistoryActivity : AppCompatActivity() {
171172
}
172173
})
173174

175+
mapboxNavigation.attachFasterRouteObserver(object : FasterRouteObserver {
176+
override fun onFasterRoute(currentRoute: DirectionsRoute, alternatives: List<DirectionsRoute>, isAlternativeFaster: Boolean) {
177+
navigationContext?.navigationMapboxMap?.drawRoutes(alternatives)
178+
navigationContext?.mapboxNavigation?.setRoutes(alternatives)
179+
}
180+
})
181+
174182
playReplay.setOnClickListener {
175183
mapboxReplayer.play()
176184
mapboxNavigation.startTripSession()
@@ -235,7 +243,7 @@ class ReplayHistoryActivity : AppCompatActivity() {
235243
override fun onRoutesReady(routes: List<DirectionsRoute>) {
236244
MapboxLogger.d(Message("route request success $routes"))
237245
if (routes.isNotEmpty()) {
238-
navigationContext?.navigationMapboxMap?.drawRoute(routes[0])
246+
navigationContext?.navigationMapboxMap?.drawRoutes(routes)
239247
navigationContext?.startNavigation()
240248
}
241249
}

libnavigation-core/src/main/java/com/mapbox/navigation/core/fasterroute/FasterRouteController.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ internal class FasterRouteController(
1919
) {
2020

2121
private val fasterRouteTimer = MapboxTimer()
22-
private val fasterRouteDetector = FasterRouteDetector()
22+
private val fasterRouteDetector = FasterRouteDetector(RouteComparator())
2323
private var fasterRouteObserver: FasterRouteObserver? = null
2424

2525
fun attach(fasterRouteObserver: FasterRouteObserver) {

libnavigation-core/src/main/java/com/mapbox/navigation/core/fasterroute/FasterRouteDetector.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ package com.mapbox.navigation.core.fasterroute
33
import com.mapbox.api.directions.v5.models.DirectionsRoute
44
import com.mapbox.navigation.base.trip.model.RouteProgress
55

6-
internal class FasterRouteDetector {
7-
fun isRouteFaster(newRoute: DirectionsRoute, routeProgress: RouteProgress): Boolean {
8-
val newRouteDuration = newRoute.duration() ?: return false
6+
internal class FasterRouteDetector(
7+
private val routeComparator: RouteComparator
8+
) {
9+
10+
fun isRouteFaster(alternativeRoute: DirectionsRoute, routeProgress: RouteProgress): Boolean {
11+
val alternativeDuration = alternativeRoute.duration() ?: return false
912
val weightedDuration = routeProgress.durationRemaining * PERCENTAGE_THRESHOLD
10-
return newRouteDuration < weightedDuration
13+
val isNewRouteFaster = alternativeDuration < weightedDuration
14+
return isNewRouteFaster && routeComparator.isNewRoute(routeProgress, alternativeRoute)
1115
}
1216

1317
companion object {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.mapbox.navigation.core.fasterroute
2+
3+
import com.mapbox.api.directions.v5.models.DirectionsRoute
4+
import com.mapbox.navigation.base.trip.model.RouteProgress
5+
6+
/**
7+
* Compares if an alternative route is different from the current route.
8+
*/
9+
internal class RouteComparator {
10+
11+
/**
12+
* @param routeProgress current route progress
13+
* @param alternativeRoute suggested new route
14+
*
15+
* @return true when the alternative route has different
16+
* geometry from the current route progress
17+
*/
18+
fun isNewRoute(routeProgress: RouteProgress, alternativeRoute: DirectionsRoute): Boolean {
19+
val currentGeometry = routeProgress.route.geometry() ?: ""
20+
val alternativeGeometry = (alternativeRoute.geometry() ?: "").ifEmpty {
21+
return false
22+
}
23+
24+
return isNewRoute(currentGeometry, alternativeGeometry)
25+
}
26+
27+
private fun isNewRoute(currentGeometry: String, alternativeGeometry: String): Boolean {
28+
return currentGeometry != alternativeGeometry
29+
}
30+
}

libnavigation-core/src/test/java/com/mapbox/navigation/core/fasterroute/FasterRouteControllerTest.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ class FasterRouteControllerTest {
122122
}
123123
every { tripSession.getRouteProgress() } returns mockk {
124124
every { durationRemaining } returns 601.334
125+
every { route } returns mockk {
126+
every { geometry() } returns "y{v|bA{}diiGOuDpBiMhM{k@~Syj@bLuZlEiM"
127+
}
125128
}
126129
every { directionsSession.requestFasterRoute(any(), capture(routesRequestCallbacks)) } returns mockk()
127130

@@ -130,6 +133,7 @@ class FasterRouteControllerTest {
130133
val routes = listOf<DirectionsRoute>(mockk {
131134
every { routeIndex() } returns "0"
132135
every { duration() } returns 351.013
136+
every { geometry() } returns "{au|bAqtiiiG|TnI`B\\dEzAl_@hMxGxB"
133137
})
134138
routesRequestCallbacks.captured.onRoutesReady(routes)
135139

libnavigation-core/src/test/java/com/mapbox/navigation/core/fasterroute/FasterRouteDetectorTest.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@ import org.junit.Test
1010

1111
class FasterRouteDetectorTest {
1212

13-
private val fasterRouteDetector = FasterRouteDetector()
13+
private val routeComparator: RouteComparator = mockk {
14+
every { isNewRoute(any(), any()) } returns true
15+
}
16+
private val fasterRouteDetector = FasterRouteDetector(routeComparator)
1417

1518
@Test
1619
fun shouldDetectWhenRouteIsFaster() {
20+
every { routeComparator.isNewRoute(any(), any()) } returns true
1721
val newRoute: DirectionsRoute = mockk()
1822
every { newRoute.duration() } returns 402.6
1923
val routeProgress: RouteProgress = mockk()
@@ -24,6 +28,19 @@ class FasterRouteDetectorTest {
2428
assertTrue(isFasterRoute)
2529
}
2630

31+
@Test
32+
fun shouldDetectWhenRouteIsFasterOnlyIfDifferent() {
33+
every { routeComparator.isNewRoute(any(), any()) } returns false
34+
val newRoute: DirectionsRoute = mockk()
35+
every { newRoute.duration() } returns 402.6
36+
val routeProgress: RouteProgress = mockk()
37+
every { routeProgress.durationRemaining } returns 797.447
38+
39+
val isFasterRoute = fasterRouteDetector.isRouteFaster(newRoute, routeProgress)
40+
41+
assertFalse(isFasterRoute)
42+
}
43+
2744
@Test
2845
fun shouldDetectWhenRouteIsSlower() {
2946
val newRoute: DirectionsRoute = mockk()
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.mapbox.navigation.core.fasterroute
2+
3+
import com.mapbox.api.directions.v5.models.DirectionsRoute
4+
import com.mapbox.navigation.base.trip.model.RouteProgress
5+
import io.mockk.every
6+
import io.mockk.mockk
7+
import junit.framework.TestCase.assertFalse
8+
import org.junit.Assert.assertTrue
9+
import org.junit.Test
10+
11+
class RouteComparatorTest {
12+
13+
private val routeComparator = RouteComparator()
14+
15+
@Test
16+
fun `route with different geometry is new`() {
17+
val currentRoute = """indacAcvqniGkFBmJB{FJ_JrEqBbAoRvEwJdBmC\sJb@eEDkEI_Mc@oIUsEF_FTgFt@qHjBmFjB}ItEqItAkE~BeW`NcEbCsNjIcCaFq@wA"""
18+
val alternative = """{{dacAiaqniGdAlIjA^vC\nD?GwX\sFgH?oJ?yF\_JtEqBz@qRtEuJxBoC?uJ|@_E?mE?aM}@oI?sE?}E^cF\yHxBkFzA_JrEmIzAmExBcWfNeExCoNnHgCuEu@yA"""
19+
val routeProgress: RouteProgress = mockk {
20+
every { route } returns mockk {
21+
every { geometry() } returns currentRoute
22+
}
23+
}
24+
val directionsRoute: DirectionsRoute = mockk {
25+
every { geometry() } returns alternative
26+
}
27+
28+
val isNewRoute = routeComparator.isNewRoute(routeProgress, directionsRoute)
29+
30+
assertTrue(isNewRoute)
31+
}
32+
33+
@Test
34+
fun `route with same geometry is not new`() {
35+
val currentRoute = """indacAcvqniGkFBmJB{FJ_JrEqBbAoRvEwJdBmC\sJb@eEDkEI_Mc@oIUsEF_FTgFt@qHjBmFjB}ItEqItAkE~BeW`NcEbCsNjIcCaFq@wA"""
36+
val alternative = """indacAcvqniGkFBmJB{FJ_JrEqBbAoRvEwJdBmC\sJb@eEDkEI_Mc@oIUsEF_FTgFt@qHjBmFjB}ItEqItAkE~BeW`NcEbCsNjIcCaFq@wA"""
37+
val routeProgress: RouteProgress = mockk {
38+
every { route } returns mockk {
39+
every { geometry() } returns currentRoute
40+
}
41+
}
42+
val directionsRoute: DirectionsRoute = mockk {
43+
every { geometry() } returns alternative
44+
}
45+
46+
val isNewRoute = routeComparator.isNewRoute(routeProgress, directionsRoute)
47+
48+
assertFalse(isNewRoute)
49+
}
50+
51+
@Test
52+
fun `alternative is not new when alternative is empty`() {
53+
val currentGeometry = """indacAcvqniGkFBmJB{FJ_JrEqBbAoRvEwJdBmC\sJb@eEDkEI_Mc@oIUsEF_FTgFt@qHjBmFjB}ItEqItAkE~BeW`NcEbCsNjIcCaFq@wA"""
54+
val alternativeGeometry = ""
55+
val routeProgress: RouteProgress = mockk {
56+
every { route } returns mockk {
57+
every { geometry() } returns currentGeometry
58+
}
59+
}
60+
val directionsRoute: DirectionsRoute = mockk {
61+
every { geometry() } returns alternativeGeometry
62+
}
63+
64+
val isNewRoute = routeComparator.isNewRoute(routeProgress, directionsRoute)
65+
66+
assertFalse(isNewRoute)
67+
}
68+
69+
@Test
70+
fun `routes with same beginning and end, can still be different`() {
71+
val currentGeometry = """e|h~bAslcjiGvBab@tHe}AnEs~@AqdAB{d@EsQCii@Ie\EeUFoh@Reg@nHwEbUsNjUuM`ZiQ|McI`e@eZbf@yX|[wRdCyAfYcQpYwPlVcOvn@y^nUqKfPwFnLeDvW{Hd^sKhr@kTzk@yd@jMuK|IqC`PrgAhM|u@nInm@pB`KnCjMbFzS`EtOrIl_@`T|{@rChMzL`i@jGbX|CzMtd@bjBbEfPdU~}@pFdTjAxDzH~XjGrSdOlc@xTvs@tUzt@jKl_@hP`d@bM``@tQ`h@vVlu@dYlw@pLl]nNrd@lApEtCdIpXpv@|AtExUpt@bXps@`Stk@lDfKlSbl@rv@~{BdD~HdIdMnOpQ|e@la@tt@|m@nEpDlItBxYhVlJ~H|P|L`LhI~SdL~FnBbXjElYbFlW`G|f@|Hpt@|J|Fm^vJs`@|Swk@jPee@j@_BpA{BrEaIfHcM~]vS`EbB"""
72+
val alternativeGeometry = """e|h~bAslcjiGvBab@tHe}AnEs~@AqdAB{d@EsQCii@Ie\EeUh`@}@ta@_@x\mAlE~YjA`IpAxGvCzSxG`c@lJjn@~AxKZvIIvDfYzSpAdAbHvFlLnEnJHvJEXtKnBdh@mCxV\~H|Jv`@zc@uKtZoIz]aKva@kKj]mIzOyDf_@mJvNcEbOqD`SmF~XiH\bOj@jXZnIX`Lt@jMt@fLnAlPn@bJ|BfS`Pg@nFOpDUde@iFbOk@fq@}BrRL|SCfBWfa@wU|[eR\SrOaJpJkFxTvs@tUzt@jKl_@hP`d@bM``@tQ`h@vVlu@dYlw@pLl]nNrd@lApEtCdIpXpv@|AtExUpt@bXps@`Stk@lDfKlSbl@rv@~{BdD~HdIdMnOpQ|e@la@tt@|m@nEpDlItBxYhVlJ~H|P|L`LhI~SdL~FnBbXjElYbFlW`G|f@|Hpt@|J|Fm^vJs`@|Swk@jPee@j@_BpA{BrEaIfHcM~]vS`EbB"""
73+
val routeProgress: RouteProgress = mockk {
74+
every { route } returns mockk {
75+
every { geometry() } returns currentGeometry
76+
}
77+
}
78+
val directionsRoute: DirectionsRoute = mockk {
79+
every { geometry() } returns alternativeGeometry
80+
}
81+
82+
val isNewRoute = routeComparator.isNewRoute(routeProgress, directionsRoute)
83+
84+
assertTrue(isNewRoute)
85+
}
86+
}

0 commit comments

Comments
 (0)