Skip to content

Commit

Permalink
NAVAND-1357 backport + NN 132.3.0 (#7215)
Browse files Browse the repository at this point in the history
  • Loading branch information
VysotskiVadim authored May 31, 2023
1 parent 4342c2c commit 8c0dbad
Show file tree
Hide file tree
Showing 18 changed files with 3,951 additions and 817 deletions.
2 changes: 2 additions & 0 deletions changelog/unreleased/bugfixes/7215.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Fixed offline-online routes switch via route alternative observer for the case when new online route is the same as current offline.
- Improved road snapping for the case when GPS signal is unstable. When GPS signal becomes unstable, LocationMatcherResult#isOffRoad stays false and LocationMatcherResult#enhancedLocation is snapped to a road, the effect takes place until stabilisation of GPS signal.
4 changes: 4 additions & 0 deletions changelog/unreleased/issues/7215.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- `NavigationRouteAlternativesObserver#onRouteAlternatives` could be called with an online alternative that is the same as current offline route except for its origin and annotations.
`MapboxNavigation#getAlternativeMetadataFor` will return null for that alternative.
Calling `MapboxNavigation#setNavigationRoutes(listOf(currentOfflinePrimaryRoute, newOnlineAlternative))` for that case won't make any effect as the alternative will be ignored.
Make sure that you implemented routes alternatives observers with respect to offline-online scenarios as documentation suggests.
2 changes: 1 addition & 1 deletion gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ ext {
// version which we should use in this build
def mapboxNavigatorVersion = System.getenv("FORCE_MAPBOX_NAVIGATION_NATIVE_VERSION")
if (mapboxNavigatorVersion == null || mapboxNavigatorVersion == '') {
mapboxNavigatorVersion = '132.2.0'
mapboxNavigatorVersion = '132.3.0'
}
println("Navigation Native version: " + mapboxNavigatorVersion)

Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mapbox.navigation.instrumentation_tests.utils

import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import com.mapbox.bindgen.Value
import com.mapbox.common.TileDataDomain
Expand All @@ -8,12 +9,15 @@ import com.mapbox.common.TileStoreOptions
import com.mapbox.navigation.base.options.NavigationOptions
import com.mapbox.navigation.base.options.RoutingTilesOptions
import com.mapbox.navigation.core.MapboxNavigation
import com.mapbox.navigation.instrumentation_tests.utils.history.MapboxHistoryTestRule
import com.mapbox.navigation.testing.ui.BaseCoreNoCleanUpTest
import com.mapbox.navigation.testing.ui.utils.coroutines.stopRecording
import java.net.URI

inline fun BaseCoreNoCleanUpTest.withMapboxNavigation(
suspend inline fun BaseCoreNoCleanUpTest.withMapboxNavigation(
useRealTiles: Boolean = false,
tileStore: TileStore? = null,
historyRecorderRule: MapboxHistoryTestRule? = null, // TODO: copy features to new infra
block: (navigation: MapboxNavigation) -> Unit
) {
val targetContext = InstrumentationRegistry.getInstrumentation().targetContext
Expand All @@ -36,9 +40,13 @@ inline fun BaseCoreNoCleanUpTest.withMapboxNavigation(
}
.build()
)
historyRecorderRule?.historyRecorder = navigation.historyRecorder
navigation.historyRecorder.startRecording()
try {
block(navigation)
} finally {
val path = navigation.historyRecorder.stopRecording()
Log.i("Test history file", "history file recorder: $path")
navigation.onDestroy()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
package com.mapbox.navigation.instrumentation_tests.utils

import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import com.mapbox.common.NetworkStatus
import com.mapbox.common.ReachabilityFactory
import com.mapbox.common.ReachabilityInterface
import com.mapbox.navigation.testing.ui.BaseCoreNoCleanUpTest
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withTimeoutOrNull
import org.junit.Assume.assumeFalse
import kotlin.coroutines.resume

private const val LOG_TAG = "TestNetwork"

suspend fun BaseCoreNoCleanUpTest.withoutInternet(block: suspend () -> Unit) {
withoutWifiAndMobileData {
Expand All @@ -12,13 +22,62 @@ suspend fun BaseCoreNoCleanUpTest.withoutInternet(block: suspend () -> Unit) {
}

suspend fun withoutWifiAndMobileData(block: suspend () -> Unit) {
val uiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation
val reachability = ReachabilityFactory.reachability(null)
Log.d(LOG_TAG, "Got request to turn internet off, checking if it was present")
reachability.waitForNetworkStatus { it != NetworkStatus.NOT_REACHABLE }
val instrumentation = InstrumentationRegistry.getInstrumentation()
val uiAutomation = instrumentation.uiAutomation
Log.d(LOG_TAG, "turning off wifi and mobile data")
uiAutomation.executeShellCommand("svc wifi disable")
uiAutomation.executeShellCommand("svc data disable")
try {
assumeNetworkIsNotReachable(reachability)
block()
} finally {
Log.d(LOG_TAG, "turning on wifi and mobile data")
uiAutomation.executeShellCommand("svc wifi enable")
uiAutomation.executeShellCommand("svc data enable")
}
Log.d(LOG_TAG, "Waiting for network to become reachable")
reachability.waitForNetworkStatus { it != NetworkStatus.NOT_REACHABLE }
}

private suspend fun assumeNetworkIsNotReachable(reachability: ReachabilityInterface) {
val networkIsReachable = withTimeoutOrNull(3000) {
reachability.waitForNetworkStatus { it == NetworkStatus.NOT_REACHABLE }
false
} ?: true
assumeFalse(
"network should not be reachable if it's turned off on device",
networkIsReachable
)
}

private suspend fun ReachabilityInterface.waitForNetworkStatus(
condition: (NetworkStatus) -> Boolean
) {
val currentStatus = currentNetworkStatus()
if (condition(currentNetworkStatus())) {
Log.d(LOG_TAG, "Network status $currentStatus is ok")
return
}
suspendCancellableCoroutine<Unit> { continuation ->
val id = this.addListener { currentStatus ->
val satisfiesCondition = condition(currentStatus)
val messageForStatus = if (satisfiesCondition) {
"Ok."
} else {
"Keep on waiting for updates."
}
Log.d("Network", "Current network status $currentStatus. $messageForStatus")
if (satisfiesCondition) {
if (continuation.isActive) {
continuation.resume(Unit)
}
}
}
continuation.invokeOnCancellation {
this.removeListener(id)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.mapbox.navigation.instrumentation_tests.utils.http

import com.mapbox.api.directions.v5.models.RouteOptions
import com.mapbox.geojson.Point
import com.mapbox.navigation.testing.ui.http.BaseMockRequestHandler
import com.mapbox.turf.TurfConstants
import com.mapbox.turf.TurfMeasurement
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.RecordedRequest

Expand All @@ -18,45 +21,77 @@ data class MockDirectionsRequestHandler constructor(
val lazyJsonResponse: () -> String,
val expectedCoordinates: List<Point>?,
val relaxedExpectedCoordinates: Boolean = false,
val coordinatesAccuracyInMeters: Double = 30.0,
) : BaseMockRequestHandler() {

constructor(
profile: String,
jsonResponse: String,
expectedCoordinates: List<Point>?,
relaxedExpectedCoordinates: Boolean = false,
) : this(profile, { jsonResponse }, expectedCoordinates, relaxedExpectedCoordinates)
coordinatesAccuracyInMeters: Double = 30.0,
) : this(
profile,
{ jsonResponse },
expectedCoordinates,
relaxedExpectedCoordinates,
coordinatesAccuracyInMeters,
)

var jsonResponseModifier: ((String) -> String) = { it }

override fun handleInternal(request: RecordedRequest): MockResponse? {
val prefix = if (relaxedExpectedCoordinates) {
"""/directions/v5/mapbox/$profile"""
} else {
"""/directions/v5/mapbox/$profile/${expectedCoordinates.parseCoordinates()}"""
}

return if (request.path!!.startsWith(prefix)) {
MockResponse().setBody(jsonResponseModifier(lazyJsonResponse()))
} else {
val routeOptions = try {
val result = RouteOptions.fromUrl(request.requestUrl!!.toUrl())
result.coordinatesList() // checks that coordinates are parsable
result
} catch (t: Throwable) {
null
}
if (routeOptions != null) {
if (relaxedExpectedCoordinates) {
return createMockResponse()
}
require(expectedCoordinates != null) {
"specify expected coordinates if they are not relaxed"
}
val coordinatesMatchExpectedAccordingToAccuracy = coordinatesWithinRadius(
expectedCoordinates,
routeOptions.coordinatesList(),
coordinatesAccuracyInMeters
)
if (coordinatesMatchExpectedAccordingToAccuracy) {
return createMockResponse()
}
}
return null
}

private fun List<Point>?.parseCoordinates(): String {
if (this == null) {
return ""
}
private fun createMockResponse() =
MockResponse().setBody(jsonResponseModifier(lazyJsonResponse()))

return this.joinToString(";") { "${it.longitude()},${it.latitude()}" }
private fun coordinatesWithinRadius(
expected: List<Point>,
actual: List<Point>,
coordinatesAccuracyInMeters: Double
): Boolean {
if (expected.size != actual.size) return false
return expected.zip(actual).all { (a, b) ->
TurfMeasurement.distance(
a,
b,
TurfConstants.UNIT_METERS
) < coordinatesAccuracyInMeters
}
}

override fun toString(): String {
return "MockDirectionsRequestHandler(" +
"profile='$profile', " +
"expectedCoordinates=$expectedCoordinates, " +
"relaxedExpectedCoordinates=$relaxedExpectedCoordinates, " +
"lazyJsonResponse='$lazyJsonResponse'" +
"lazyJsonResponse='$lazyJsonResponse', " +
"coordinatesAccuracyInMeters='$coordinatesAccuracyInMeters'" +
")"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ suspend fun BaseCoreNoCleanUpTest.stayOnPosition(
latitude: Double,
longitude: Double,
bearing: Float,
frequencyHz: Int = 10,
frequencyHz: Int = 1,
block: suspend () -> Unit
) {
coroutineScope {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ object OfflineRegions {
)
}

// covers Berlin partially to support EvRoutesProvider.getBerlinEvRoute
private val BERLIN_GEOMETRY = FeatureCollection.fromJson(
readRawFileText(
InstrumentationRegistry.getInstrumentation().targetContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.mapbox.common.TileRegionLoadOptions
import com.mapbox.geojson.Geometry
import com.mapbox.navigation.core.MapboxNavigation
import com.mapbox.navigation.instrumentation_tests.utils.createTileStore
import com.mapbox.navigation.instrumentation_tests.utils.history.MapboxHistoryTestRule
import com.mapbox.navigation.instrumentation_tests.utils.withMapboxNavigation
import com.mapbox.navigation.testing.ui.BaseCoreNoCleanUpTest
import kotlinx.coroutines.suspendCancellableCoroutine
Expand Down Expand Up @@ -44,11 +45,13 @@ suspend fun loadRegion(navigation: MapboxNavigation, region: OfflineRegion) {

suspend inline fun BaseCoreNoCleanUpTest.withMapboxNavigationAndOfflineTilesForRegion(
region: OfflineRegion,
historyRecorderRule: MapboxHistoryTestRule? = null,
block: (MapboxNavigation) -> Unit
) {
withMapboxNavigation(
useRealTiles = true, // TODO: use mocked tiles instead of real NAVAND-1351
tileStore = createTileStore()
tileStore = createTileStore(),
historyRecorderRule = historyRecorderRule
) { navigation ->
loadRegion(navigation, region)
block(navigation)
Expand Down
20 changes: 10 additions & 10 deletions instrumentation-tests/src/main/res/raw/geometry_berlin.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,24 @@
"coordinates": [
[
[
13.03807042990934,
52.70072965030741
13.332149046468828,
52.52171498620973
],
[
13.03807042990934,
52.32726294794662
13.332149046468828,
52.489117728511985
],
[
13.818542568562549,
52.32726294794662
13.424292486579304,
52.489117728511985
],
[
13.818542568562549,
52.70072965030741
13.424292486579304,
52.52171498620973
],
[
13.03807042990934,
52.70072965030741
13.332149046468828,
52.52171498620973
]
]
],
Expand Down
Loading

0 comments on commit 8c0dbad

Please sign in to comment.