Skip to content

Commit 7582b5e

Browse files
yuryybkgithub-actions[bot]
authored andcommitted
NAVAND-6001 Expose unavailable EV station status (#10030)
* NAVAND-6001 Use type-safe Directions notifications; expose the reason for the unavailable charging station GitOrigin-RevId: b5bc781368fd9578ef4681a30e7b2094c05be1ff
1 parent 4be844b commit 7582b5e

11 files changed

Lines changed: 726 additions & 802 deletions

File tree

base/src/main/java/com/mapbox/navigation/base/internal/route/NavigationRouteEx.kt

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package com.mapbox.navigation.base.internal.route
55

66
import androidx.annotation.RestrictTo
77
import androidx.annotation.WorkerThread
8-
import com.google.gson.JsonArray
98
import com.google.gson.JsonElement
109
import com.google.gson.JsonPrimitive
1110
import com.mapbox.api.directions.v5.models.Closure
@@ -15,12 +14,12 @@ import com.mapbox.api.directions.v5.models.DirectionsWaypoint
1514
import com.mapbox.api.directions.v5.models.Incident
1615
import com.mapbox.api.directions.v5.models.LegAnnotation
1716
import com.mapbox.api.directions.v5.models.LegStep
17+
import com.mapbox.api.directions.v5.models.Notification
1818
import com.mapbox.api.directions.v5.models.RouteLeg
1919
import com.mapbox.api.directionsrefresh.v1.models.DirectionsRouteRefresh
2020
import com.mapbox.navigation.base.ExperimentalMapboxNavigationAPI
2121
import com.mapbox.navigation.base.internal.CongestionNumericOverride
2222
import com.mapbox.navigation.base.internal.utils.Constants
23-
import com.mapbox.navigation.base.internal.utils.Constants.RouteResponse.KEY_NOTIFICATIONS
2423
import com.mapbox.navigation.base.internal.utils.Constants.RouteResponse.KEY_REFRESH_TTL
2524
import com.mapbox.navigation.base.route.NavigationRoute
2625
import com.mapbox.navigation.base.route.RouteRefreshMetadata
@@ -58,8 +57,8 @@ fun NavigationRoute.internalRefreshRoute(
5857
routeRefresh.legs()?.map { it.annotation() },
5958
routeRefresh.legs()?.map { it.incidents() },
6059
routeRefresh.legs()?.map { it.closures() },
60+
routeRefresh.legs()?.map { it.notifications() },
6161
updatedWaypoints,
62-
routeRefresh.legs()?.map { it.unrecognizedJsonProperties?.get(KEY_NOTIFICATIONS) },
6362
responseTimeElapsedSeconds,
6463
routeRefresh.unrecognizedJsonProperties
6564
?.get(KEY_REFRESH_TTL)?.asInt,
@@ -81,8 +80,8 @@ fun NavigationRoute.refreshRoute(
8180
legAnnotations: List<LegAnnotation?>?,
8281
incidents: List<List<Incident>?>?,
8382
closures: List<List<Closure>?>?,
83+
notifications: List<List<Notification>?>?,
8484
waypoints: List<DirectionsWaypoint?>?,
85-
unrecognizedLegNotifications: List<JsonElement?>?,
8685
responseTimeElapsedSeconds: Long,
8786
refreshTtl: Int?,
8887
): NavigationRoute {
@@ -92,8 +91,8 @@ fun NavigationRoute.refreshRoute(
9291
legAnnotations,
9392
incidents,
9493
closures,
94+
notifications,
9595
waypoints,
96-
unrecognizedLegNotifications,
9796
responseTimeElapsedSeconds,
9897
refreshTtl,
9998
IncidentsRefresher(),
@@ -109,8 +108,8 @@ internal fun NavigationRoute.refreshRoute(
109108
legAnnotations: List<LegAnnotation?>?,
110109
incidents: List<List<Incident>?>?,
111110
closures: List<List<Closure>?>?,
111+
notifications: List<List<Notification>?>?,
112112
waypoints: List<DirectionsWaypoint?>?,
113-
unrecognizedLegNotifications: List<JsonElement?>?,
114113
responseTimeElapsedSeconds: Long,
115114
refreshTtl: Int?,
116115
incidentsRefresher: IncidentsRefresher,
@@ -156,9 +155,10 @@ internal fun NavigationRoute.refreshRoute(
156155
startingLegGeometryIndex,
157156
lastLegRefreshIndex,
158157
)
158+
159159
val mergedNotifications = notificationsRefresher.getRefreshedNotifications(
160-
routeLeg.unrecognizedJsonProperties?.get(KEY_NOTIFICATIONS) as? JsonArray,
161-
unrecognizedLegNotifications?.getOrNull(index) as? JsonArray,
160+
routeLeg.notifications(),
161+
notifications?.getOrNull(index),
162162
startingLegGeometryIndex,
163163
lastLegRefreshIndex,
164164
)
@@ -168,8 +168,8 @@ internal fun NavigationRoute.refreshRoute(
168168
.annotation(mergedAnnotation)
169169
.incidents(mergedIncidents)
170170
.closures(mergedClosures)
171+
.notifications(mergedNotifications)
171172
.steps(routeLeg.steps()?.updateSteps(directionsRoute, mergedAnnotation))
172-
.applyMergedNotifications(routeLeg.unrecognizedJsonProperties, mergedNotifications)
173173
.build()
174174
}
175175
}
@@ -332,18 +332,3 @@ private fun DirectionsRoute.Builder.updateRouteDurationBasedOnLegsDurationAndCha
332332
duration(result)
333333
return this
334334
}
335-
336-
private fun RouteLeg.Builder.applyMergedNotifications(
337-
oldUnrecognizedProperties: Map<String, JsonElement>?,
338-
mergedNotifications: JsonArray?,
339-
): RouteLeg.Builder {
340-
return unrecognizedJsonProperties(
341-
oldUnrecognizedProperties.orEmpty().toMutableMap().also {
342-
if (mergedNotifications == null || mergedNotifications.isEmpty) {
343-
it.remove(KEY_NOTIFICATIONS)
344-
} else {
345-
it[KEY_NOTIFICATIONS] = mergedNotifications
346-
}
347-
},
348-
)
349-
}
Lines changed: 46 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,150 +1,117 @@
11
package com.mapbox.navigation.base.internal.route
22

3-
import com.google.gson.JsonArray
4-
import com.google.gson.JsonElement
5-
import com.mapbox.navigation.base.internal.utils.Constants.NotificationRefreshType.DYNAMIC
3+
import com.mapbox.api.directions.v5.DirectionsCriteria.NOTIFICATION_REFRESH_TYPE_DYNAMIC
4+
import com.mapbox.api.directions.v5.models.Notification
65

76
internal class NotificationsRefresher {
87

98
fun getRefreshedNotifications(
10-
oldNotifications: JsonArray?,
11-
newNotifications: JsonArray?,
9+
oldNotifications: List<Notification>?,
10+
newNotifications: List<Notification>?,
1211
startingLegGeometryIndex: Int,
1312
lastRefreshLegGeometryIndex: Int,
14-
): JsonArray? {
15-
return when {
13+
): List<Notification>? {
14+
val result = when {
1615
oldNotifications == null && newNotifications == null -> null
1716
oldNotifications == null -> adjustNotificationIndices(
18-
newNotifications,
17+
newNotifications.orEmpty(),
1918
startingLegGeometryIndex,
2019
)
20+
2121
newNotifications == null -> filterNotificationsByGeometryRange(
2222
oldNotifications,
2323
startingLegGeometryIndex,
2424
lastRefreshLegGeometryIndex,
2525
)
26+
2627
else -> mergeNotifications(
2728
oldNotifications,
2829
newNotifications,
2930
startingLegGeometryIndex,
3031
lastRefreshLegGeometryIndex,
3132
)
3233
}
34+
35+
return result?.takeIf { it.isNotEmpty() }
3336
}
3437

3538
private fun mergeNotifications(
36-
oldNotifications: JsonArray,
37-
newNotifications: JsonArray,
39+
oldNotifications: List<Notification>,
40+
newNotifications: List<Notification>,
3841
startingLegGeometryIndex: Int,
3942
lastRefreshLegGeometryIndex: Int,
40-
): JsonArray {
43+
): List<Notification> {
4144
// Filter old notifications to keep static and dynamic notifications outside refresh range
42-
val result = filterNotificationsByGeometryRange(
45+
val oldFiltered = filterNotificationsByGeometryRange(
4346
oldNotifications,
4447
startingLegGeometryIndex,
4548
lastRefreshLegGeometryIndex,
4649
)
4750

4851
// Add new dynamic notifications with adjusted indices
49-
result.addAll(
50-
adjustNotificationIndices(
51-
newNotifications,
52-
startingLegGeometryIndex,
53-
),
52+
val newAdjusted = adjustNotificationIndices(
53+
newNotifications,
54+
startingLegGeometryIndex,
5455
)
5556

56-
return result
57+
return oldFiltered + newAdjusted
5758
}
5859

5960
private fun filterNotificationsByGeometryRange(
60-
notifications: JsonArray,
61+
notifications: List<Notification>,
6162
startingLegGeometryIndex: Int,
6263
lastRefreshLegGeometryIndex: Int,
63-
): JsonArray {
64-
val result = JsonArray()
65-
66-
notifications.forEach { notification ->
67-
if (notification.isDynamicNotification()) {
64+
): List<Notification> =
65+
notifications.mapNotNull { notification ->
66+
if (notification.isDynamic) {
6867
// Dynamic notifications: only keep those outside the refresh range
69-
val geometryIndex = notification.getGeometryIndex()
68+
val geometryIndex = notification.geometryIndex()
7069
if (geometryIndex != null) {
7170
val isOutsideRange = geometryIndex < startingLegGeometryIndex ||
7271
geometryIndex > lastRefreshLegGeometryIndex
7372
if (isOutsideRange) {
74-
result.add(notification)
73+
return@mapNotNull notification
7574
}
7675
}
7776
// Dynamic notifications without geometry_index are filtered out
77+
null
7878
} else {
7979
// Static notifications: always keep them
80-
result.add(notification)
80+
notification
8181
}
8282
}
8383

84-
return result
85-
}
86-
8784
/**
8885
* Adjusts geometry indices for new notifications using the provided starting leg geometry index.
8986
*/
9087
private fun adjustNotificationIndices(
91-
notifications: JsonArray?,
88+
notifications: List<Notification>,
9289
startingLegGeometryIndex: Int,
93-
): JsonArray? {
94-
if (notifications == null || notifications.isEmpty) {
95-
return notifications
96-
}
97-
98-
val result = JsonArray()
99-
notifications.forEach { notification ->
100-
val adjustedNotification = adjustNotificationIndex(
90+
): List<Notification> =
91+
notifications.map { notification ->
92+
adjustNotificationIndex(
10193
notification,
10294
startingLegGeometryIndex,
10395
)
104-
result.add(adjustedNotification)
10596
}
106-
return result
107-
}
10897

10998
private fun adjustNotificationIndex(
110-
notification: JsonElement,
99+
notification: Notification,
111100
startingLegGeometryIndex: Int,
112-
): JsonElement {
113-
if (!notification.isJsonObject) {
114-
return notification
115-
}
116-
117-
val notificationObject = notification.asJsonObject
118-
val geometryIndex = notificationObject.get("geometry_index")?.asInt
119-
120-
if (geometryIndex != null) {
121-
val adjustedNotification = notificationObject.deepCopy()
122-
adjustedNotification.addProperty(
123-
"geometry_index",
124-
startingLegGeometryIndex + geometryIndex,
125-
)
126-
return adjustedNotification
127-
}
128-
129-
return notification
130-
}
131-
132-
private fun JsonElement.getGeometryIndex(): Int? {
133-
return if (isJsonObject) {
134-
asJsonObject.get("geometry_index")?.asInt
135-
} else {
136-
null
137-
}
101+
): Notification {
102+
return notification.toBuilder().apply {
103+
notification.geometryIndex()?.let {
104+
geometryIndex(it + startingLegGeometryIndex)
105+
}
106+
notification.geometryIndexStart()?.let {
107+
geometryIndexStart(it + startingLegGeometryIndex)
108+
}
109+
notification.geometryIndexEnd()?.let {
110+
geometryIndexEnd(it + startingLegGeometryIndex)
111+
}
112+
}.build()
138113
}
139114

140-
/**
141-
* Determines if a notification should be treated as dynamic (refreshable)
142-
* based on the refresh_type field
143-
*/
144-
private fun JsonElement.isDynamicNotification(): Boolean {
145-
if (!isJsonObject) return false
146-
147-
val refreshType = asJsonObject.get("refresh_type")?.asJsonPrimitive?.asString
148-
return refreshType == DYNAMIC
149-
}
115+
private val Notification.isDynamic: Boolean
116+
get() = refreshType() == NOTIFICATION_REFRESH_TYPE_DYNAMIC
150117
}

base/src/main/java/com/mapbox/navigation/base/internal/utils/Constants.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ class Constants {
44
object RouteResponse {
55
const val KEY_WAYPOINTS = "waypoints"
66
const val KEY_REFRESH_TTL = "refresh_ttl"
7-
const val KEY_NOTIFICATIONS = "notifications"
87
}
98

109
object CongestionRange {
@@ -13,9 +12,4 @@ class Constants {
1312
val HEAVY_CONGESTION_RANGE = 60..79
1413
val SEVERE_CONGESTION_RANGE = 80..100
1514
}
16-
17-
internal object NotificationRefreshType {
18-
const val STATIC = "static"
19-
const val DYNAMIC = "dynamic"
20-
}
2115
}

0 commit comments

Comments
 (0)