Skip to content

Commit a3da3ba

Browse files
author
Łukasz Paczos
committed
fixed an issue with state while reroute request is interrupted by a new reroute request
1 parent a2b3b6a commit a3da3ba

File tree

3 files changed

+62
-38
lines changed

3 files changed

+62
-38
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Mapbox welcomes participation and contributions from everyone.
99
#### Bug fixes and improvements
1010
- Fixed approaches list update in `RouteOptionsUpdater`(uses for reroute). It was putting to the origin approach corresponding approach from legacy approach list. [#6540](https://github.com/mapbox/mapbox-navigation-android/pull/6540)
1111
- Updated the `MapboxRestAreaApi` logic to load a SAPA map only if the upcoming rest stop is at the current step of the route leg. [#6695](https://github.com/mapbox/mapbox-navigation-android/pull/6695)
12+
- Fixed an issue where `MapboxRerouteController` could deliver a delayed interruption state notifications. Now, the interruption state is always delivered synchronously, as soon as it's available. [#6718](https://github.com/mapbox/mapbox-navigation-android/pull/6718)
1213

1314
## Mapbox Navigation SDK 2.9.5 - 13 December, 2022
1415
### Changelog

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

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ import com.mapbox.navigation.utils.internal.JobControl
2020
import com.mapbox.navigation.utils.internal.ThreadController
2121
import com.mapbox.navigation.utils.internal.ifNonNull
2222
import com.mapbox.navigation.utils.internal.logD
23-
import com.mapbox.navigation.utils.internal.logW
23+
import com.mapbox.navigation.utils.internal.logI
2424
import kotlinx.coroutines.Job
25-
import kotlinx.coroutines.cancel
2625
import kotlinx.coroutines.launch
2726
import kotlinx.coroutines.suspendCancellableCoroutine
2827
import java.util.concurrent.CopyOnWriteArraySet
@@ -44,8 +43,6 @@ internal class MapboxRerouteController @VisibleForTesting constructor(
4443

4544
private val mainJobController: JobControl = threadController.getMainScopeAndRootJob()
4645

47-
private var requestId: Long? = null
48-
4946
private var rerouteJob: Job? = null
5047

5148
constructor(
@@ -70,17 +67,6 @@ internal class MapboxRerouteController @VisibleForTesting constructor(
7067
return
7168
}
7269
field = value
73-
when (value) {
74-
RerouteState.Idle,
75-
RerouteState.Interrupted,
76-
is RerouteState.Failed,
77-
is RerouteState.RouteFetched -> {
78-
requestId = null
79-
}
80-
RerouteState.FetchingRoute -> {
81-
// no impl
82-
}
83-
}
8470
observers.forEach { it.onRerouteStateChanged(field) }
8571
}
8672

@@ -189,18 +175,14 @@ internal class MapboxRerouteController @VisibleForTesting constructor(
189175

190176
@MainThread
191177
override fun interrupt() {
178+
rerouteJob?.cancel()
179+
rerouteJob = null
192180
if (state == RerouteState.FetchingRoute) {
193-
requestId?.also { id ->
194-
directionsSession.cancelRouteRequest(id)
195-
logD(LOG_CATEGORY) {
196-
"Route request interrupted"
197-
}
198-
} ?: logW(LOG_CATEGORY) {
199-
"Tried interrupting but there's no ongoing request"
181+
logI(LOG_CATEGORY) {
182+
"Request interrupted via controller"
200183
}
201-
rerouteJob?.cancel()
202-
rerouteJob = null
203184
}
185+
onRequestInterrupted()
204186
}
205187

206188
override fun registerRerouteStateObserver(
@@ -223,8 +205,7 @@ internal class MapboxRerouteController @VisibleForTesting constructor(
223205
routeOptions: RouteOptions
224206
) {
225207
rerouteJob = mainJobController.scope.launch {
226-
val result = requestAsync(routeOptions)
227-
when (result) {
208+
when (val result = requestAsync(routeOptions)) {
228209
is RouteRequestResult.Success -> {
229210
mainJobController.scope.launch {
230211
state = RerouteState.RouteFetched(result.routerOrigin)
@@ -241,7 +222,12 @@ internal class MapboxRerouteController @VisibleForTesting constructor(
241222
state = RerouteState.Idle
242223
}
243224
}
244-
is RouteRequestResult.Cancellation -> onRequestInterrupted()
225+
is RouteRequestResult.Cancellation -> {
226+
if (state == RerouteState.FetchingRoute) {
227+
logI("Request canceled via router")
228+
}
229+
onRequestInterrupted()
230+
}
245231
}
246232
}
247233
}
@@ -251,16 +237,15 @@ internal class MapboxRerouteController @VisibleForTesting constructor(
251237
}
252238

253239
private fun onRequestInterrupted() {
254-
mainJobController.scope.launch {
240+
if (state == RerouteState.FetchingRoute) {
255241
state = RerouteState.Interrupted
256242
state = RerouteState.Idle
257243
}
258244
}
259245

260246
private suspend fun requestAsync(routeOptions: RouteOptions): RouteRequestResult {
261247
return suspendCancellableCoroutine { cont ->
262-
cont.invokeOnCancellation { onRequestInterrupted() }
263-
requestId = directionsSession.requestRoutes(
248+
val requestId = directionsSession.requestRoutes(
264249
routeOptions,
265250
object : NavigationRouterCallback {
266251
override fun onRoutesReady(
@@ -291,6 +276,9 @@ internal class MapboxRerouteController @VisibleForTesting constructor(
291276
}
292277
}
293278
)
279+
cont.invokeOnCancellation {
280+
directionsSession.cancelRouteRequest(requestId)
281+
}
294282
}
295283
}
296284
}

libnavigation-core/src/test/java/com/mapbox/navigation/core/reroute/MapboxRerouteControllerTest.kt

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class MapboxRerouteControllerTest {
4949

5050
private lateinit var rerouteController: MapboxRerouteController
5151

52-
@MockK
52+
@MockK(relaxUnitFun = true)
5353
private lateinit var directionsSession: DirectionsSession
5454

5555
@MockK
@@ -317,25 +317,57 @@ class MapboxRerouteControllerTest {
317317

318318
@Test
319319
fun reroute_calls_interrupt_if_currently_fetching() = coroutineRule.runBlockingTest {
320-
mockRouteOptionsResult(successFromResult)
321-
val routeRequestCallback = slot<NavigationRouterCallback>()
320+
addRerouteStateObserver()
321+
val routeOptions1 = MapboxJavaObjectsFactory.routeOptions(
322+
coordinates = listOf(Point.fromLngLat(1.0, 2.0), Point.fromLngLat(3.0, 4.0))
323+
)
324+
val updaterSuccess1 = RouteOptionsUpdater.RouteOptionsResult.Success(routeOptions1)
325+
val routeOptions2 = MapboxJavaObjectsFactory.routeOptions(
326+
coordinates = listOf(Point.fromLngLat(1.5, 2.5), Point.fromLngLat(3.0, 4.0))
327+
)
328+
val updaterSuccess2 = RouteOptionsUpdater.RouteOptionsResult.Success(routeOptions2)
329+
val routeRequestCallback1 = slot<NavigationRouterCallback>()
322330
every {
323331
directionsSession.requestRoutes(
324-
routeOptionsFromSuccessResult,
325-
capture(routeRequestCallback)
332+
routeOptions1,
333+
capture(routeRequestCallback1)
326334
)
327335
} returns 1L
328-
rerouteController.reroute(routeCallback)
336+
val routeRequestCallback2 = slot<NavigationRouterCallback>()
337+
every {
338+
directionsSession.requestRoutes(
339+
routeOptions2,
340+
capture(routeRequestCallback2)
341+
)
342+
} returns 2L
329343

344+
mockRouteOptionsResult(updaterSuccess1)
330345
rerouteController.reroute(routeCallback)
331-
routeRequestCallback.captured.onRoutesReady(listOf(mockk(relaxed = true)), mockk())
346+
pauseDispatcher {
347+
// this ensure that we don't run coroutines synchronously that could
348+
// make the test pass even if state changes were scheduled back to the message queue
349+
// in an incorrect order
350+
mockRouteOptionsResult(updaterSuccess2)
351+
rerouteController.reroute(routeCallback)
352+
verify(exactly = 1) { directionsSession.cancelRouteRequest(1L) }
353+
routeRequestCallback1.captured.onCanceled(routeOptions1, mockk())
354+
}
355+
356+
routeRequestCallback2.captured.onRoutesReady(listOf(mockk(relaxed = true)), mockk())
332357

333-
verify(exactly = 1) { directionsSession.cancelRouteRequest(1L) }
358+
verifyOrder {
359+
primaryRerouteObserver.onRerouteStateChanged(RerouteState.FetchingRoute)
360+
primaryRerouteObserver.onRerouteStateChanged(RerouteState.Interrupted)
361+
primaryRerouteObserver.onRerouteStateChanged(RerouteState.Idle)
362+
primaryRerouteObserver.onRerouteStateChanged(RerouteState.FetchingRoute)
363+
primaryRerouteObserver.onRerouteStateChanged(ofType<RerouteState.RouteFetched>())
364+
}
334365
}
335366

336367
@Test
337368
fun reroute_only_calls_interrupt_if_currently_fetching() {
338369
mockRouteOptionsResult(successFromResult)
370+
addRerouteStateObserver()
339371
val routeRequestCallback = slot<NavigationRouterCallback>()
340372
every {
341373
directionsSession.requestRoutes(
@@ -349,6 +381,9 @@ class MapboxRerouteControllerTest {
349381

350382
verify(exactly = 0) { directionsSession.cancelAll() }
351383
verify(exactly = 0) { directionsSession.cancelRouteRequest(any()) }
384+
verify(exactly = 0) {
385+
primaryRerouteObserver.onRerouteStateChanged(RerouteState.Interrupted)
386+
}
352387
}
353388

354389
@Test

0 commit comments

Comments
 (0)