Skip to content

Commit 592818b

Browse files
dzinadŁukasz Paczos
andauthored
NAVAND-775: support waypoints per route (#6555)
* NAVAND-775: support waypoints per route * use NavigationRoute#waypoints in BillingController * fix NavigationRoute#waypoitns docs Co-authored-by: Łukasz Paczos <lukasz.paczos@mapbox.com>
1 parent 4b43089 commit 592818b

File tree

23 files changed

+1379
-377
lines changed

23 files changed

+1379
-377
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Mapbox welcomes participation and contributions from everyone.
1919
- Fixed a rare issue where the offset marking the traveled portion of the route would be ahead of the user location puck, especially around sharp maneuvers. [#6648](https://github.com/mapbox/mapbox-navigation-android/pull/6648)
2020
- Supported applying latest EV data provided via `MapboxNavigation#onEVDataUpdated` to EV reroute requests. [#6650](https://github.com/mapbox/mapbox-navigation-android/pull/6650)
2121
- Fixed an issue where reroute requests where not applying the latest EV data provided via `MapboxNavigation#onEVDataUpdated`. [#6650](https://github.com/mapbox/mapbox-navigation-android/pull/6650)
22+
- Added `NavigationRoute#waypoints` as the source of truth for `DirectionsWaypoint`s which can be common for all routes or route specific depending on `RouteOptions#waypointsPerRoute()` parameter. [#6555](https://github.com/mapbox/mapbox-navigation-android/pull/6555)
2223

2324
## Mapbox Navigation SDK 2.9.2 - 18 November, 2022
2425
### Changelog
@@ -37,7 +38,6 @@ This release depends on, and has been tested with, the following Mapbox dependen
3738
- Mapbox Java `v6.9.0` ([release notes](https://github.com/mapbox/mapbox-java/releases/tag/v6.9.0))
3839
- Mapbox Android Core `v5.0.2` ([release notes](https://github.com/mapbox/mapbox-events-android/releases/tag/core-5.0.2))
3940

40-
4141
## Mapbox Navigation SDK 2.10.0-beta.1 - 18 November, 2022
4242
### Changelog
4343
[Changes between v2.10.0-alpha.3 and v2.10.0-beta.1](https://github.com/mapbox/mapbox-navigation-android/compare/v2.10.0-alpha.3...v2.10.0-beta.1)

instrumentation-tests/src/androidTest/java/com/mapbox/navigation/instrumentation_tests/core/EVRouteRefreshTest.kt

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import com.mapbox.api.directionsrefresh.v1.models.DirectionsRefreshResponse
99
import com.mapbox.geojson.Point
1010
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
1111
import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions
12+
import com.mapbox.navigation.base.internal.utils.internalWaypoints
1213
import com.mapbox.navigation.base.options.NavigationOptions
1314
import com.mapbox.navigation.base.options.RoutingTilesOptions
1415
import com.mapbox.navigation.base.route.NavigationRoute
@@ -31,6 +32,7 @@ import com.mapbox.navigation.instrumentation_tests.utils.http.MockDirectionsRefr
3132
import com.mapbox.navigation.instrumentation_tests.utils.http.MockDirectionsRequestHandler
3233
import com.mapbox.navigation.instrumentation_tests.utils.location.MockLocationReplayerRule
3334
import com.mapbox.navigation.instrumentation_tests.utils.readRawFileText
35+
import com.mapbox.navigation.instrumentation_tests.utils.toApproximateCoordinates
3436
import com.mapbox.navigation.testing.ui.BaseTest
3537
import com.mapbox.navigation.testing.ui.utils.getMapboxAccessTokenFromResources
3638
import com.mapbox.navigation.testing.ui.utils.runOnMainSync
@@ -348,6 +350,53 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
348350
)
349351
}
350352

353+
@Test
354+
fun ev_route_refresh_updates_waypoints_per_route() = sdkTest {
355+
replaceOriginalResponseHandler(R.raw.ev_route_response_for_refresh_with_waypoints_per_route)
356+
addRefreshRequestHandler(
357+
R.raw.ev_route_refresh_response,
358+
acceptedGeometryIndex = 0,
359+
testUuid = "ev_route_response_for_refresh_with_waypoints_per_route"
360+
)
361+
val requestedRoutes = requestRoutes(
362+
twoCoordinates,
363+
electric = true,
364+
waypointsPerRoute = true
365+
)
366+
val evData = mapOf(
367+
KEY_ENERGY_CONSUMPTION_CURVE to "0,300;20,160;80,140;120,180",
368+
KEY_EV_INITIAL_CHARGE to "17000",
369+
KEY_EV_PRECONDITIONING_TIME to "10",
370+
KEY_AUXILIARY_CONSUMPTION to "300"
371+
)
372+
mapboxNavigation.onEVDataUpdated(evData)
373+
374+
mapboxNavigation.setNavigationRoutesAndWaitForUpdate(requestedRoutes)
375+
mapboxNavigation.startTripSession()
376+
stayOnInitialPosition()
377+
val updatedRoutes = waitUntilRefresh().navigationRoutes
378+
379+
assertEquals(
380+
listOf(null, 8097, null),
381+
requestedRoutes[0].waypoints?.extractChargeAtArrival()
382+
)
383+
384+
assertEquals(
385+
listOf(null, 7286, null),
386+
updatedRoutes[0].waypoints?.extractChargeAtArrival()
387+
)
388+
assertEquals(updatedRoutes[0].directionsRoute.waypoints(), updatedRoutes[0].waypoints)
389+
val tolerance = 0.00001
390+
assertEquals(
391+
updatedRoutes[0].internalWaypoints().map {
392+
it.name to it.location.toApproximateCoordinates(tolerance)
393+
},
394+
updatedRoutes[0].waypoints?.map {
395+
it.name() to it.location().toApproximateCoordinates(tolerance)
396+
}
397+
)
398+
}
399+
351400
@Test
352401
fun ev_route_refresh_updates_ev_annotations_and_waypoints_for_truncated_current_leg() =
353402
sdkTest {
@@ -539,12 +588,14 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
539588
electric: Boolean,
540589
minChargeAtDestination: Int,
541590
initialCharge: String,
591+
waypointsPerRoute: Boolean?,
542592
): RouteOptions {
543593
return RouteOptions.builder().applyDefaultNavigationOptions()
544594
.profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC)
545595
.alternatives(true)
546596
.enableRefresh(true)
547597
.coordinatesList(coordinates)
598+
.waypointsPerRoute(waypointsPerRoute)
548599
.baseUrl(mockWebServerRule.baseUrl) // Comment out to test a real server
549600
.apply {
550601
if (electric) {
@@ -589,10 +640,17 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
589640
coordinates: List<Point>,
590641
electric: Boolean,
591642
minChargeAtDestination: Int = 6000,
592-
initialCharge: String = initialInitialCharge
643+
initialCharge: String = initialInitialCharge,
644+
waypointsPerRoute: Boolean? = null,
593645
): List<NavigationRoute> {
594646
return mapboxNavigation.requestRoutes(
595-
generateRouteOptions(coordinates, electric, minChargeAtDestination, initialCharge)
647+
generateRouteOptions(
648+
coordinates,
649+
electric,
650+
minChargeAtDestination,
651+
initialCharge,
652+
waypointsPerRoute
653+
)
596654
)
597655
.getSuccessfulResultOrThrowException()
598656
.routes
@@ -640,7 +698,7 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
640698
return MockDirectionsRefreshHandler(
641699
testUuid,
642700
readRawFileText(activity, fileId),
643-
acceptedGeometryIndex = acceptedGeometryIndex
701+
acceptedGeometryIndex = acceptedGeometryIndex,
644702
).also {
645703
mockWebServerRule.requestHandlers.add(FailByRequestMockRequestHandler(it))
646704
}
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
package com.mapbox.navigation.instrumentation_tests.core
2+
3+
import android.location.Location
4+
import androidx.annotation.IdRes
5+
import com.mapbox.api.directions.v5.DirectionsCriteria
6+
import com.mapbox.api.directions.v5.models.RouteOptions
7+
import com.mapbox.geojson.Point
8+
import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions
9+
import com.mapbox.navigation.base.internal.utils.internalWaypoints
10+
import com.mapbox.navigation.base.options.NavigationOptions
11+
import com.mapbox.navigation.base.options.RoutingTilesOptions
12+
import com.mapbox.navigation.base.route.NavigationRoute
13+
import com.mapbox.navigation.core.MapboxNavigation
14+
import com.mapbox.navigation.core.MapboxNavigationProvider
15+
import com.mapbox.navigation.instrumentation_tests.R
16+
import com.mapbox.navigation.instrumentation_tests.activity.EmptyTestActivity
17+
import com.mapbox.navigation.instrumentation_tests.utils.ApproximateCoordinates
18+
import com.mapbox.navigation.instrumentation_tests.utils.MapboxNavigationRule
19+
import com.mapbox.navigation.instrumentation_tests.utils.coroutines.getSuccessfulResultOrThrowException
20+
import com.mapbox.navigation.instrumentation_tests.utils.coroutines.requestRoutes
21+
import com.mapbox.navigation.instrumentation_tests.utils.coroutines.sdkTest
22+
import com.mapbox.navigation.instrumentation_tests.utils.http.MockDirectionsRequestHandler
23+
import com.mapbox.navigation.instrumentation_tests.utils.location.MockLocationReplayerRule
24+
import com.mapbox.navigation.instrumentation_tests.utils.readRawFileText
25+
import com.mapbox.navigation.instrumentation_tests.utils.toApproximateCoordinates
26+
import com.mapbox.navigation.testing.ui.BaseTest
27+
import com.mapbox.navigation.testing.ui.utils.getMapboxAccessTokenFromResources
28+
import com.mapbox.navigation.testing.ui.utils.runOnMainSync
29+
import org.junit.Assert.assertEquals
30+
import org.junit.Assert.assertNull
31+
import org.junit.Before
32+
import org.junit.Rule
33+
import org.junit.Test
34+
import java.net.URI
35+
36+
class WaypointsTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.java) {
37+
38+
@get:Rule
39+
val mapboxNavigationRule = MapboxNavigationRule()
40+
41+
@get:Rule
42+
val mockLocationReplayerRule = MockLocationReplayerRule(mockLocationUpdatesRule)
43+
44+
private val evCoordinates = listOf(
45+
Point.fromLngLat(11.5852259, 48.1760993),
46+
Point.fromLngLat(10.3406374, 49.16479)
47+
)
48+
49+
private val nonEvCoordinates = listOf(
50+
Point.fromLngLat(-121.496066, 38.577764),
51+
Point.fromLngLat(-121.480279, 38.57674),
52+
Point.fromLngLat(-121.468434, 38.58225)
53+
)
54+
55+
private lateinit var mapboxNavigation: MapboxNavigation
56+
private val tolerance = 0.00001
57+
private val expectedEvWaypointsNamesAndLocations = listOf(
58+
"Leopoldstraße" to ApproximateCoordinates(48.176099, 11.585226, tolerance),
59+
"" to ApproximateCoordinates(48.39023, 11.063842, tolerance),
60+
"" to ApproximateCoordinates(49.164725, 10.340713, tolerance),
61+
)
62+
private val expectedFirstNonEvWaypointsNamesAndLocations = listOf(
63+
"9th Street" to ApproximateCoordinates(38.577764, -121.496066, tolerance),
64+
"J Street" to ApproximateCoordinates(38.576795, -121.480256, tolerance),
65+
"C Street" to ApproximateCoordinates(38.582195, -121.468458, tolerance),
66+
)
67+
private val expectedSecondNonEvWaypointsNamesAndLocations = listOf(
68+
"9th Street" to ApproximateCoordinates(38.577764, -121.496066, tolerance),
69+
"J Street" to ApproximateCoordinates(38.576795, -121.480256, tolerance),
70+
"C Street changed for tests" to ApproximateCoordinates(38.582195, -121.468458, tolerance),
71+
)
72+
73+
override fun setupMockLocation(): Location = mockLocationUpdatesRule.generateLocationUpdate {
74+
latitude = nonEvCoordinates[0].latitude()
75+
longitude = nonEvCoordinates[0].longitude()
76+
bearing = 190f
77+
}
78+
79+
@Before
80+
fun setup() {
81+
runOnMainSync {
82+
mapboxNavigation = MapboxNavigationProvider.create(
83+
NavigationOptions.Builder(activity)
84+
.accessToken(getMapboxAccessTokenFromResources(activity))
85+
.routingTilesOptions(
86+
RoutingTilesOptions.Builder()
87+
.tilesBaseUri(URI(mockWebServerRule.baseUrl))
88+
.build()
89+
)
90+
.navigatorPredictionMillis(0L)
91+
.build()
92+
)
93+
mockWebServerRule.requestHandlers.clear()
94+
}
95+
}
96+
97+
@Test
98+
fun ev_route_with_waypoints_in_response_root_by_default() = sdkTest {
99+
addResponseHandler(R.raw.ev_route_response_with_waypoints_in_root, evCoordinates)
100+
val routes = requestRoutes(evCoordinates, electric = true, waypointsPerRoute = null)
101+
102+
checkWaypointsInRoot(expectedEvWaypointsNamesAndLocations, routes[0])
103+
}
104+
105+
@Test
106+
fun ev_route_with_waypoints_in_response_root() = sdkTest {
107+
addResponseHandler(R.raw.ev_route_response_with_waypoints_in_root, evCoordinates)
108+
val routes = requestRoutes(evCoordinates, electric = true, waypointsPerRoute = false)
109+
110+
checkWaypointsInRoot(expectedEvWaypointsNamesAndLocations, routes[0])
111+
}
112+
113+
@Test
114+
fun ev_route_with_waypoints_per_route() = sdkTest {
115+
addResponseHandler(R.raw.ev_route_response_with_waypoints_per_route, evCoordinates)
116+
val routes = requestRoutes(evCoordinates, electric = true, waypointsPerRoute = true)
117+
118+
checkWaypointsPerRoute(expectedEvWaypointsNamesAndLocations, routes[0])
119+
}
120+
121+
@Test
122+
fun non_ev_route_with_waypoints_in_response_root_by_default() = sdkTest {
123+
addResponseHandler(R.raw.route_response_with_waypoints_in_root, nonEvCoordinates)
124+
val routes = requestRoutes(nonEvCoordinates, electric = false, waypointsPerRoute = null)
125+
126+
checkWaypointsInRoot(expectedFirstNonEvWaypointsNamesAndLocations, routes[0])
127+
checkWaypointsInRoot(expectedFirstNonEvWaypointsNamesAndLocations, routes[1])
128+
}
129+
130+
@Test
131+
fun non_ev_route_with_waypoints_in_response_root() = sdkTest {
132+
addResponseHandler(R.raw.route_response_with_waypoints_in_root, nonEvCoordinates)
133+
val routes = requestRoutes(nonEvCoordinates, electric = false, waypointsPerRoute = false)
134+
135+
checkWaypointsInRoot(expectedFirstNonEvWaypointsNamesAndLocations, routes[0])
136+
checkWaypointsInRoot(expectedFirstNonEvWaypointsNamesAndLocations, routes[1])
137+
}
138+
139+
@Test
140+
fun non_ev_route_with_waypoints_per_route() = sdkTest {
141+
addResponseHandler(R.raw.route_response_with_waypoints_per_route, nonEvCoordinates)
142+
val routes = requestRoutes(nonEvCoordinates, electric = false, waypointsPerRoute = true)
143+
144+
checkWaypointsPerRoute(expectedFirstNonEvWaypointsNamesAndLocations, routes[0])
145+
checkWaypointsPerRoute(expectedSecondNonEvWaypointsNamesAndLocations, routes[1])
146+
}
147+
148+
private suspend fun requestRoutes(
149+
coordinates: List<Point>,
150+
electric: Boolean,
151+
waypointsPerRoute: Boolean? = null,
152+
): List<NavigationRoute> {
153+
return mapboxNavigation.requestRoutes(
154+
generateRouteOptions(coordinates, electric, waypointsPerRoute)
155+
)
156+
.getSuccessfulResultOrThrowException()
157+
.routes
158+
}
159+
160+
private fun generateRouteOptions(
161+
coordinates: List<Point>,
162+
electric: Boolean,
163+
waypointsPerRoute: Boolean?,
164+
): RouteOptions {
165+
return RouteOptions.builder().applyDefaultNavigationOptions()
166+
.profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC)
167+
.alternatives(true)
168+
.coordinatesList(coordinates)
169+
.waypointsPerRoute(waypointsPerRoute)
170+
.baseUrl(mockWebServerRule.baseUrl) // Comment out to test a real server
171+
.apply {
172+
if (electric) {
173+
annotations("state_of_charge")
174+
unrecognizedProperties(
175+
mapOf(
176+
"engine" to "electric",
177+
"ev_initial_charge" to "18000",
178+
"energy_consumption_curve" to "0,300;20,160;80,140;120,180",
179+
"ev_pre_conditioning_time" to "10",
180+
"ev_min_charge_at_charging_station" to "6000",
181+
"ev_min_charge_at_destination" to "6000",
182+
"ev_max_charge" to "60000",
183+
"ev_connector_types" to "ccs_combo_type1,ccs_combo_type2",
184+
"energy_consumption_curve" to "0,300;20,160;80,140;120,180",
185+
"ev_charging_curve" to "0,100000;40000,70000;60000,30000;80000,10000",
186+
"ev_max_ac_charging_power" to "14400",
187+
"ev_unconditioned_charging_curve" to
188+
"0,50000;42000,35000;60000,15000;80000,5000",
189+
"auxiliary_consumption" to "300",
190+
)
191+
)
192+
}
193+
}
194+
.build()
195+
}
196+
197+
private fun checkWaypointsInRoot(
198+
expected: List<Pair<String, ApproximateCoordinates>>,
199+
route: NavigationRoute,
200+
) {
201+
assertEquals(
202+
expected,
203+
route.waypoints!!.map {
204+
it.name() to it.location().toApproximateCoordinates(tolerance)
205+
}
206+
)
207+
assertEquals(
208+
expected,
209+
route.internalWaypoints().map {
210+
it.name to it.location.toApproximateCoordinates(tolerance)
211+
}
212+
)
213+
assertEquals(
214+
expected,
215+
route.directionsResponse.waypoints()!!.map {
216+
it.name() to it.location().toApproximateCoordinates(tolerance)
217+
}
218+
)
219+
assertNull(route.directionsRoute.waypoints())
220+
}
221+
222+
private fun checkWaypointsPerRoute(
223+
expected: List<Pair<String, ApproximateCoordinates>>,
224+
route: NavigationRoute,
225+
) {
226+
assertEquals(
227+
expected,
228+
route.waypoints!!.map {
229+
it.name() to it.location().toApproximateCoordinates(tolerance)
230+
}
231+
)
232+
assertEquals(
233+
expected,
234+
route.internalWaypoints().map {
235+
it.name to it.location.toApproximateCoordinates(tolerance)
236+
}
237+
)
238+
assertEquals(
239+
expected,
240+
route.directionsRoute.waypoints()!!.map {
241+
it.name() to it.location().toApproximateCoordinates(tolerance)
242+
}
243+
)
244+
assertNull(route.directionsResponse.waypoints())
245+
}
246+
247+
private fun addResponseHandler(@IdRes fileId: Int, coordinates: List<Point>) {
248+
val routeHandler = MockDirectionsRequestHandler(
249+
"driving-traffic",
250+
readRawFileText(activity, fileId),
251+
coordinates,
252+
relaxedExpectedCoordinates = true
253+
)
254+
mockWebServerRule.requestHandlers.add(routeHandler)
255+
}
256+
}

0 commit comments

Comments
 (0)