Skip to content

Commit 868e038

Browse files
committed
NAVAND-842: use initial EV data in EV route refresh
1 parent 1fba6ba commit 868e038

File tree

10 files changed

+362
-87
lines changed

10 files changed

+362
-87
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Mapbox welcomes participation and contributions from everyone.
3636
- Slightly improved performance of updates to the traveled portion of the route in MapboxRouteLineView. [#6528](https://github.com/mapbox/mapbox-navigation-android/pull/6528)
3737
- Fixed an issue with `NavigationView` that caused road label position to not update in some cases. [#6531](https://github.com/mapbox/mapbox-navigation-android/pull/6531)
3838
- Fixed an issue where `DirectionsResponse#waypoints` list was cleared after a successful non-EV route refresh. [#6539](https://github.com/mapbox/mapbox-navigation-android/pull/6539)
39+
- Fixed an issue with EV route refresh failing in cases where EV data updates are not provided. Now, the initial parameters from a route request will be used as a fallback. [#6534](https://github.com/mapbox/mapbox-navigation-android/pull/6534)
3940

4041
## Mapbox Navigation SDK 2.10.0-alpha.1 - 28 October, 2022
4142
### Changelog

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

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
7777
Point.fromLngLat(10.3406374, 49.16479)
7878
)
7979
private lateinit var routeHandler: MockDirectionsRequestHandler
80+
private val initialEnergyConsumptionCurve = "0,300;20,160;80,140;120,180"
81+
private val initialInitialCharge = "18000"
82+
private val initialAuxiliaryConsumption = "300"
83+
private val initialEvPreconditioningTime = "10"
8084

8185
override fun setupMockLocation(): Location = mockLocationUpdatesRule.generateLocationUpdate {
8286
latitude = twoCoordinates[0].latitude()
@@ -150,20 +154,42 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
150154
R.raw.ev_route_refresh_response,
151155
acceptedGeometryIndex = 0
152156
)
157+
refreshHandler.jsonResponseModifier = DynamicResponseModifier()
153158
val requestedRoutes = requestRoutes(twoCoordinates, electric = true)
154159

155160
mapboxNavigation.startTripSession()
156161
stayOnInitialPosition()
157162
mapboxNavigation.setNavigationRoutes(requestedRoutes)
158163
waitUntilRefresh()
159164

160-
checkDoesNotHaveParameters(
165+
checkHasParameters(
161166
refreshHandler.handledRequests.first().requestUrl!!,
162-
evDataKeys
167+
mapOf(
168+
KEY_ENGINE to VALUE_ELECTRIC,
169+
KEY_ENERGY_CONSUMPTION_CURVE to initialEnergyConsumptionCurve,
170+
KEY_EV_INITIAL_CHARGE to initialInitialCharge,
171+
KEY_AUXILIARY_CONSUMPTION to initialAuxiliaryConsumption,
172+
KEY_EV_PRECONDITIONING_TIME to initialEvPreconditioningTime,
173+
)
174+
)
175+
176+
val newInitialCharge = "17900"
177+
val newRequestedRoutes = requestRoutes(
178+
twoCoordinates,
179+
electric = true,
180+
initialCharge = newInitialCharge
163181
)
182+
mapboxNavigation.setNavigationRoutes(newRequestedRoutes)
183+
waitUntilNewRefresh()
164184
checkHasParameters(
165-
refreshHandler.handledRequests.first().requestUrl!!,
166-
mapOf(KEY_ENGINE to VALUE_ELECTRIC)
185+
refreshHandler.handledRequests.last().requestUrl!!,
186+
mapOf(
187+
KEY_ENGINE to VALUE_ELECTRIC,
188+
KEY_ENERGY_CONSUMPTION_CURVE to initialEnergyConsumptionCurve,
189+
KEY_EV_INITIAL_CHARGE to newInitialCharge,
190+
KEY_AUXILIARY_CONSUMPTION to initialAuxiliaryConsumption,
191+
KEY_EV_PRECONDITIONING_TIME to initialEvPreconditioningTime,
192+
)
167193
)
168194
}
169195

@@ -212,14 +238,22 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
212238
mapboxNavigation.setNavigationRoutes(requestedRoutes)
213239
waitUntilRefresh()
214240

215-
val noUpdaterRefreshUrl = refreshHandler.handledRequests.first().requestUrl!!
216-
checkDoesNotHaveParameters(noUpdaterRefreshUrl, evDataKeys)
217-
checkHasParameters(noUpdaterRefreshUrl, mapOf(KEY_ENGINE to VALUE_ELECTRIC))
241+
val noDataRefreshUrl = refreshHandler.handledRequests.first().requestUrl!!
242+
checkHasParameters(
243+
noDataRefreshUrl,
244+
mapOf(
245+
KEY_ENGINE to VALUE_ELECTRIC,
246+
KEY_ENERGY_CONSUMPTION_CURVE to initialEnergyConsumptionCurve,
247+
KEY_EV_PRECONDITIONING_TIME to initialEvPreconditioningTime,
248+
KEY_EV_INITIAL_CHARGE to initialInitialCharge,
249+
KEY_EV_INITIAL_CHARGE to initialInitialCharge,
250+
)
251+
)
218252

219-
val consumptionCurve = "0,300;20,120;40,150"
253+
val consumptionCurve = "0,301;20,121;40,151"
220254
val initialCharge = "80"
221-
val preconditioningTime = "10"
222-
val auxiliaryConsumption = "300"
255+
val preconditioningTime = "11"
256+
val auxiliaryConsumption = "299"
223257
val firstEvData = mapOf(
224258
KEY_ENERGY_CONSUMPTION_CURVE to consumptionCurve,
225259
KEY_EV_INITIAL_CHARGE to initialCharge,
@@ -236,10 +270,7 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
236270

237271
val newInitialCharge = "60"
238272
mapboxNavigation.onEVDataUpdated(
239-
mapOf(
240-
KEY_EV_INITIAL_CHARGE to newInitialCharge,
241-
KEY_EV_PRECONDITIONING_TIME to null,
242-
)
273+
mapOf(KEY_EV_INITIAL_CHARGE to newInitialCharge)
243274
)
244275
waitUntilNewRefresh()
245276

@@ -250,10 +281,10 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
250281
KEY_ENGINE to VALUE_ELECTRIC,
251282
KEY_ENERGY_CONSUMPTION_CURVE to consumptionCurve,
252283
KEY_EV_INITIAL_CHARGE to newInitialCharge,
253-
KEY_AUXILIARY_CONSUMPTION to auxiliaryConsumption
284+
KEY_AUXILIARY_CONSUMPTION to auxiliaryConsumption,
285+
KEY_EV_PRECONDITIONING_TIME to preconditioningTime,
254286
)
255287
)
256-
checkDoesNotHaveParameters(urlWithTwiceUpdatedData, setOf(KEY_EV_PRECONDITIONING_TIME))
257288

258289
mapboxNavigation.onEVDataUpdated(emptyMap())
259290
waitUntilNewRefresh()
@@ -265,10 +296,10 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
265296
KEY_ENGINE to VALUE_ELECTRIC,
266297
KEY_ENERGY_CONSUMPTION_CURVE to consumptionCurve,
267298
KEY_EV_INITIAL_CHARGE to newInitialCharge,
268-
KEY_AUXILIARY_CONSUMPTION to auxiliaryConsumption
299+
KEY_AUXILIARY_CONSUMPTION to auxiliaryConsumption,
300+
KEY_EV_PRECONDITIONING_TIME to preconditioningTime,
269301
)
270302
)
271-
checkDoesNotHaveParameters(urlAfterEmptyUpdate, setOf(KEY_EV_PRECONDITIONING_TIME))
272303
}
273304

274305
@Test
@@ -279,7 +310,7 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
279310
)
280311
val requestedRoutes = requestRoutes(twoCoordinates, electric = true)
281312
val evData = mapOf(
282-
KEY_ENERGY_CONSUMPTION_CURVE to "0,300;20,160;80,140;120,180",
313+
KEY_ENERGY_CONSUMPTION_CURVE to initialEnergyConsumptionCurve,
283314
KEY_EV_INITIAL_CHARGE to "17000",
284315
KEY_EV_PRECONDITIONING_TIME to "10",
285316
KEY_AUXILIARY_CONSUMPTION to "300"
@@ -328,7 +359,7 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
328359
)
329360
val requestedRoutes = requestRoutes(twoCoordinates, electric = true)
330361
val evData = mapOf(
331-
KEY_ENERGY_CONSUMPTION_CURVE to "0,300;20,160;80,140;120,180",
362+
KEY_ENERGY_CONSUMPTION_CURVE to initialEnergyConsumptionCurve,
332363
KEY_EV_INITIAL_CHARGE to "17000",
333364
KEY_EV_PRECONDITIONING_TIME to "10",
334365
KEY_AUXILIARY_CONSUMPTION to "300"
@@ -379,7 +410,7 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
379410
)
380411
val requestedRoutes = requestRoutes(twoCoordinates, electric = true)
381412
val evData = mapOf(
382-
KEY_ENERGY_CONSUMPTION_CURVE to "0,300;20,160;80,140;120,180",
413+
KEY_ENERGY_CONSUMPTION_CURVE to initialEnergyConsumptionCurve,
383414
KEY_EV_INITIAL_CHARGE to "17000",
384415
KEY_EV_PRECONDITIONING_TIME to "10",
385416
KEY_AUXILIARY_CONSUMPTION to "300"
@@ -434,7 +465,7 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
434465
minChargeAtDestination = 35000
435466
)
436467
val evData = mapOf(
437-
KEY_ENERGY_CONSUMPTION_CURVE to "0,300;20,160;80,140;120,180",
468+
KEY_ENERGY_CONSUMPTION_CURVE to initialEnergyConsumptionCurve,
438469
KEY_EV_INITIAL_CHARGE to "30000",
439470
KEY_EV_PRECONDITIONING_TIME to "10",
440471
KEY_AUXILIARY_CONSUMPTION to "300"
@@ -512,6 +543,7 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
512543
coordinates: List<Point>,
513544
electric: Boolean,
514545
minChargeAtDestination: Int,
546+
initialCharge: String,
515547
): RouteOptions {
516548
return RouteOptions.builder().applyDefaultNavigationOptions()
517549
.profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC)
@@ -525,19 +557,18 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
525557
unrecognizedProperties(
526558
mapOf(
527559
KEY_ENGINE to VALUE_ELECTRIC,
528-
KEY_EV_INITIAL_CHARGE to "18000",
529-
KEY_ENERGY_CONSUMPTION_CURVE to "0,300;20,160;80,140;120,180",
530-
KEY_EV_PRECONDITIONING_TIME to "10",
560+
KEY_EV_INITIAL_CHARGE to initialCharge,
561+
KEY_ENERGY_CONSUMPTION_CURVE to initialEnergyConsumptionCurve,
562+
KEY_EV_PRECONDITIONING_TIME to initialEvPreconditioningTime,
563+
KEY_AUXILIARY_CONSUMPTION to initialAuxiliaryConsumption,
531564
"ev_min_charge_at_charging_station" to "6000",
532565
"ev_min_charge_at_destination" to "$minChargeAtDestination",
533566
"ev_max_charge" to "60000",
534567
"ev_connector_types" to "ccs_combo_type1,ccs_combo_type2",
535-
"energy_consumption_curve" to "0,300;20,160;80,140;120,180",
536568
"ev_charging_curve" to "0,100000;40000,70000;60000,30000;80000,10000",
537569
"ev_max_ac_charging_power" to "14400",
538570
"ev_unconditioned_charging_curve" to
539571
"0,50000;42000,35000;60000,15000;80000,5000",
540-
"auxiliary_consumption" to "300",
541572
)
542573
)
543574
}
@@ -562,10 +593,11 @@ class EVRouteRefreshTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.
562593
private suspend fun requestRoutes(
563594
coordinates: List<Point>,
564595
electric: Boolean,
565-
minChargeAtDestination: Int = 6000
596+
minChargeAtDestination: Int = 6000,
597+
initialCharge: String = initialInitialCharge
566598
): List<NavigationRoute> {
567599
return mapboxNavigation.requestRoutes(
568-
generateRouteOptions(coordinates, electric, minChargeAtDestination)
600+
generateRouteOptions(coordinates, electric, minChargeAtDestination, initialCharge)
569601
)
570602
.getSuccessfulResultOrThrowException()
571603
.routes

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

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,18 +1697,11 @@ class MapboxNavigation @VisibleForTesting internal constructor(
16971697
* "auxiliary_consumption" to "300"
16981698
* )
16991699
* ```
1700-
* If you want to remove a parameter, pass `null` for the corresponding key.
1701-
* Example: for the case above if you want to remove "auxiliary_consumption", invoke this method
1702-
* with
1703-
* ```
1704-
* mapOf("auxiliary_consumption" to null)
1705-
* ```
1706-
* as an argument.
17071700
*
17081701
* @param data Map describing the changed EV data
17091702
*/
17101703
@ExperimentalPreviewMapboxNavigationAPI
1711-
fun onEVDataUpdated(data: Map<String, String?>) {
1704+
fun onEVDataUpdated(data: Map<String, String>) {
17121705
routeRefreshRequestDataProvider.onEVDataUpdated(data)
17131706
}
17141707

@@ -1739,7 +1732,7 @@ class MapboxNavigation @VisibleForTesting internal constructor(
17391732

17401733
private fun createInternalRoutesObserver() = RoutesObserver { result ->
17411734
latestLegIndex = null
1742-
routeRefreshRequestDataProvider.onNewRoute()
1735+
routeRefreshRequestDataProvider.onNewRoutes()
17431736
if (result.navigationRoutes.isNotEmpty()) {
17441737
routeScope.launch {
17451738
val refreshed = routeRefreshController.refresh(

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.mapbox.navigation.core
22

33
import androidx.annotation.MainThread
4+
import com.mapbox.api.directions.v5.models.RouteOptions
45
import com.mapbox.navigation.base.internal.RouteRefreshRequestData
56
import com.mapbox.navigation.base.trip.model.RouteProgress
67
import com.mapbox.navigation.core.routerefresh.EVDataHolder
@@ -30,26 +31,25 @@ internal class RouteRefreshRequestDataProvider(
3031
/**
3132
* Returns either last saved value (if has one) or waits for the next update.
3233
*/
33-
suspend fun getRouteRefreshRequestDataOrWait(): RouteRefreshRequestData {
34+
suspend fun getRouteRefreshRequestDataOrWait(
35+
routeOptions: RouteOptions
36+
): RouteRefreshRequestData {
3437
return (routeProgressData ?: suspendCancellableCoroutine { continuation = it }).let {
3538
RouteRefreshRequestData(
3639
it.legIndex,
3740
it.routeGeometryIndex,
3841
it.legGeometryIndex,
39-
evDataHolder.currentData()
42+
evDataHolder.currentData(routeOptions.unrecognizedJsonProperties)
4043
)
4144
}
4245
}
4346

44-
/**
45-
* Resets saved route data info to null.
46-
*/
47-
fun onNewRoute() {
47+
fun onNewRoutes() {
4848
routeProgressData = null
4949
}
5050

51-
fun onEVDataUpdated(data: Map<String, String?>) {
52-
evDataHolder.onEVDataUpdated(data)
51+
fun onEVDataUpdated(data: Map<String, String>) {
52+
evDataHolder.updateData(data)
5353
}
5454

5555
override fun onRouteProgressChanged(routeProgress: RouteProgress) {
Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,63 @@
11
package com.mapbox.navigation.core.routerefresh
22

3+
import com.google.gson.JsonElement
4+
35
internal class EVDataHolder {
46

7+
private val evRefreshKeys = setOf(
8+
"energy_consumption_curve",
9+
"ev_initial_charge",
10+
"auxiliary_consumption",
11+
"ev_pre_conditioning_time",
12+
)
513
private val currentData = mutableMapOf<String, String>()
614

715
@Synchronized
8-
fun onEVDataUpdated(data: Map<String, String?>) {
9-
data.forEach { (key, value) ->
10-
if (value == null) {
11-
currentData.remove(key)
12-
} else {
13-
currentData[key] = value
16+
fun updateData(data: Map<String, String>) {
17+
currentData.putAll(data)
18+
}
19+
20+
@Synchronized
21+
fun currentData(initialData: Map<String, JsonElement>?): Map<String, String> = mergeEvData(
22+
initialData,
23+
HashMap(currentData)
24+
)
25+
26+
private fun mergeEvData(
27+
unrecognizedProperties: Map<String, JsonElement>?,
28+
latestUpdate: Map<String, String>
29+
): Map<String, String> {
30+
val result = HashMap<String, String>(latestUpdate)
31+
val fallbackData = extractEvRefreshData(unrecognizedProperties)
32+
fallbackData.forEach { (key, value) ->
33+
if (key !in result.keys) {
34+
result[key] = value
1435
}
1536
}
37+
return result
1638
}
1739

18-
@Synchronized
19-
fun currentData(): Map<String, String> = HashMap(currentData)
40+
private fun extractEvRefreshData(
41+
unrecognizedProperties: Map<String, JsonElement>?
42+
): Map<String, String> {
43+
val result = mutableMapOf<String, String>()
44+
if (unrecognizedProperties != null) {
45+
val engine = unrecognizedProperties["engine"]
46+
?.asStringOrNull()
47+
if (engine == "electric") {
48+
evRefreshKeys.forEach { key ->
49+
unrecognizedProperties[key]?.asStringOrNull()?.let { value ->
50+
result[key] = value
51+
}
52+
}
53+
}
54+
}
55+
return result
56+
}
57+
58+
private fun JsonElement.asStringOrNull(): String? = try {
59+
asString
60+
} catch (ex: Throwable) {
61+
null
62+
}
2063
}

libnavigation-core/src/main/java/com/mapbox/navigation/core/routerefresh/RouteRefreshController.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ internal class RouteRefreshController(
142142
}
143143

144144
private suspend fun refreshRoutesWithRetry(
145-
routes: List<NavigationRoute>
145+
routes: List<NavigationRoute> // non-empty
146146
): RefreshedRouteInfo = coroutineScope {
147147
var timeUntilNextAttempt = async { delay(routeRefreshOptions.intervalMillis) }
148148
try {
@@ -153,7 +153,7 @@ internal class RouteRefreshController(
153153
}
154154
timeUntilNextAttempt = async { delay(routeRefreshOptions.intervalMillis) }
155155
val routeRefreshRequestData = routeRefreshRequestDataProvider
156-
.getRouteRefreshRequestDataOrWait()
156+
.getRouteRefreshRequestDataOrWait(routes.first().routeOptions)
157157
val refreshedRoutes = refreshRoutesOrNull(routes, routeRefreshRequestData)
158158
if (refreshedRoutes.any { it != null }) {
159159
onNewState(RouteRefreshExtra.REFRESH_STATE_FINISHED_SUCCESS)
@@ -169,7 +169,8 @@ internal class RouteRefreshController(
169169
timeUntilNextAttempt.cancel() // otherwise current coroutine will wait for its child
170170
}
171171
onNewState(RouteRefreshExtra.REFRESH_STATE_FINISHED_FAILED)
172-
val requestData = routeRefreshRequestDataProvider.getRouteRefreshRequestDataOrWait()
172+
val requestData = routeRefreshRequestDataProvider
173+
.getRouteRefreshRequestDataOrWait(routes.first().routeOptions)
173174
RefreshedRouteInfo(
174175
routes.map { removeExpiringDataFromRoute(it, requestData.legIndex) },
175176
requestData

0 commit comments

Comments
 (0)