Skip to content

Commit 3c323da

Browse files
committed
prototyping
1 parent f0dc41b commit 3c323da

File tree

13 files changed

+637
-91
lines changed

13 files changed

+637
-91
lines changed

examples/src/main/java/com/mapbox/navigation/examples/core/MapboxNavigationActivity.kt

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import android.view.View.VISIBLE
1010
import android.widget.Toast
1111
import androidx.appcompat.app.AppCompatActivity
1212
import androidx.core.content.ContextCompat
13+
import androidx.lifecycle.lifecycleScope
1314
import com.mapbox.api.directions.v5.models.RouteOptions
1415
import com.mapbox.bindgen.Expected
1516
import com.mapbox.geojson.Point
@@ -52,6 +53,7 @@ import com.mapbox.navigation.ui.maps.location.NavigationLocationProvider
5253
import com.mapbox.navigation.ui.maps.route.arrow.api.MapboxRouteArrowApi
5354
import com.mapbox.navigation.ui.maps.route.arrow.api.MapboxRouteArrowView
5455
import com.mapbox.navigation.ui.maps.route.arrow.model.RouteArrowOptions
56+
import com.mapbox.navigation.ui.maps.route.line.MapboxRouteLineApiExtensions.setNavigationRoutes
5557
import com.mapbox.navigation.ui.maps.route.line.MapboxRouteLineApiExtensions.setRoutes
5658
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi
5759
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineView
@@ -89,6 +91,8 @@ class MapboxNavigationActivity : AppCompatActivity() {
8991
// location puck integration
9092
private val navigationLocationProvider = NavigationLocationProvider()
9193

94+
private val waypoints = mutableListOf<Point>()
95+
9296
// camera
9397
private lateinit var navigationCamera: NavigationCamera
9498
private lateinit var viewportDataSource: MapboxNavigationViewportDataSource
@@ -229,15 +233,19 @@ class MapboxNavigationActivity : AppCompatActivity() {
229233
}
230234

231235
private val routesObserver = RoutesObserver { result ->
232-
if (result.routes.isNotEmpty()) {
236+
if (result.navigationRoutes.isNotEmpty()) {
233237
// generate route geometries asynchronously and render them
234-
CoroutineScope(Dispatchers.Main).launch {
235-
val result = routeLineAPI.setRoutes(
236-
listOf(RouteLine(result.routes.first(), null))
237-
)
238-
val style = mapboxMap.getStyle()
239-
if (style != null) {
240-
routeLineView.renderRouteDrawData(style, result)
238+
lifecycleScope.launch {
239+
routeLineAPI.setNavigationRoutes(
240+
newRoutes = result.navigationRoutes,
241+
alternativeRoutesMetadata = mapboxNavigation.getAlternativeMetadataFor(
242+
result.navigationRoutes
243+
)
244+
).apply {
245+
routeLineView.renderRouteDrawData(
246+
binding.mapView.getMapboxMap().getStyle()!!,
247+
this
248+
)
241249
}
242250
}
243251

@@ -399,7 +407,7 @@ class MapboxNavigationActivity : AppCompatActivity() {
399407
routeLineView.initializeLayers(style)
400408
// add long click listener that search for a route to the clicked destination
401409
binding.mapView.gestures.addOnMapLongClickListener { point ->
402-
findRoute(point)
410+
addWaypoint(point)
403411
true
404412
}
405413
}
@@ -460,24 +468,26 @@ class MapboxNavigationActivity : AppCompatActivity() {
460468
voiceInstructionsPlayer.shutdown()
461469
}
462470

463-
private fun findRoute(destination: Point) {
471+
private fun addWaypoint(destination: Point) {
464472
val origin = navigationLocationProvider.lastLocation?.let {
465473
Point.fromLngLat(it.longitude, it.latitude)
466474
} ?: return
467475

476+
waypoints.add(destination)
477+
468478
mapboxNavigation.requestRoutes(
469479
RouteOptions.builder()
470480
.applyDefaultNavigationOptions()
471481
.applyLanguageAndVoiceUnitOptions(this)
472-
.coordinatesList(listOf(origin, destination))
473-
.layersList(listOf(mapboxNavigation.getZLevel(), null))
482+
.alternatives(true)
483+
.coordinatesList(listOf(origin) + waypoints)
474484
.build(),
475485
object : NavigationRouterCallback {
476486
override fun onRoutesReady(
477487
routes: List<NavigationRoute>,
478488
routerOrigin: RouterOrigin
479489
) {
480-
setRouteAndStartNavigation(routes)
490+
setRoutePreview(routes)
481491
}
482492

483493
override fun onFailure(
@@ -494,9 +504,25 @@ class MapboxNavigationActivity : AppCompatActivity() {
494504
)
495505
}
496506

497-
private fun setRouteAndStartNavigation(route: List<NavigationRoute>) {
507+
508+
509+
private fun setRoutePreview(route: List<NavigationRoute>) {
498510
// set route
499-
mapboxNavigation.setNavigationRoutes(route)
511+
mapboxNavigation.previewNavigationRoutes(route)
512+
binding.navigate.visibility = VISIBLE
513+
binding.navigate.setOnClickListener {
514+
setRoute()
515+
binding.navigate.visibility = INVISIBLE
516+
}
517+
518+
// move the camera to overview when new route is available
519+
navigationCamera.requestNavigationCameraToOverview()
520+
}
521+
522+
private fun setRoute() {
523+
// set route
524+
mapboxNavigation.setNavigationRoutes(mapboxNavigation.getPreviewedNavigationRoutes())
525+
waypoints.clear()
500526

501527
// show UI elements
502528
binding.soundButton.visibility = VISIBLE
@@ -506,12 +532,12 @@ class MapboxNavigationActivity : AppCompatActivity() {
506532
binding.soundButton.unmuteAndExtend(2000L)
507533

508534
// move the camera to overview when new route is available
509-
navigationCamera.requestNavigationCameraToOverview()
535+
navigationCamera.requestNavigationCameraToFollowing()
510536
}
511537

512538
private fun clearRouteAndStopNavigation() {
513539
// clear
514-
mapboxNavigation.setRoutes(listOf())
540+
mapboxNavigation.clearRoutes()
515541

516542
// hide UI elements
517543
binding.soundButton.visibility = INVISIBLE

examples/src/main/res/layout/layout_activity_navigation.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@
1313
app:layout_constraintStart_toStartOf="parent"
1414
app:layout_constraintTop_toTopOf="parent" />
1515

16+
<Button
17+
android:layout_width="match_parent"
18+
android:layout_height="wrap_content"
19+
android:id="@+id/navigate"
20+
android:visibility="invisible"
21+
android:text="Navigate"
22+
app:layout_constraintBottom_toBottomOf="parent"
23+
app:layout_constraintStart_toStartOf="parent"
24+
app:layout_constraintEnd_toEndOf="parent"/>
25+
1626
<androidx.cardview.widget.CardView
1727
android:id="@+id/tripProgressCard"
1828
android:layout_width="0dp"
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package com.mapbox.navigation.instrumentation_tests.core
2+
3+
import android.location.Location
4+
import com.mapbox.navigation.base.options.NavigationOptions
5+
import com.mapbox.navigation.base.route.NavigationRoute
6+
import com.mapbox.navigation.core.MapboxNavigation
7+
import com.mapbox.navigation.core.MapboxNavigationProvider
8+
import com.mapbox.navigation.core.directions.session.RoutesExtra
9+
import com.mapbox.navigation.core.trip.session.NavigationSessionState
10+
import com.mapbox.navigation.core.trip.session.NavigationSessionStateV2
11+
import com.mapbox.navigation.instrumentation_tests.activity.EmptyTestActivity
12+
import com.mapbox.navigation.instrumentation_tests.utils.MapboxNavigationRule
13+
import com.mapbox.navigation.instrumentation_tests.utils.coroutines.sdkTest
14+
import com.mapbox.navigation.instrumentation_tests.utils.coroutines.waitForNewRoute
15+
import com.mapbox.navigation.instrumentation_tests.utils.coroutines.waitForPreviewRoute
16+
import com.mapbox.navigation.instrumentation_tests.utils.coroutines.waitForRoutesCleanUp
17+
import com.mapbox.navigation.instrumentation_tests.utils.routes.RoutesProvider
18+
import com.mapbox.navigation.instrumentation_tests.utils.routes.RoutesProvider.toNavigationRoutes
19+
import com.mapbox.navigation.testing.ui.BaseTest
20+
import com.mapbox.navigation.testing.ui.utils.getMapboxAccessTokenFromResources
21+
import com.mapbox.navigation.testing.ui.utils.runOnMainSync
22+
import kotlinx.coroutines.async
23+
import org.junit.Assert.assertEquals
24+
import org.junit.Assert.assertNotNull
25+
import org.junit.Assert.assertTrue
26+
import org.junit.Before
27+
import org.junit.Rule
28+
import org.junit.Test
29+
import java.util.Objects
30+
import kotlin.reflect.typeOf
31+
32+
class PreviewRoutesTest : BaseTest<EmptyTestActivity>(EmptyTestActivity::class.java) {
33+
34+
override fun setupMockLocation(): Location = mockLocationUpdatesRule.generateLocationUpdate {
35+
latitude = 38.894721
36+
longitude = -77.031991
37+
}
38+
39+
@get:Rule
40+
val mapboxNavigationRule = MapboxNavigationRule()
41+
private lateinit var mapboxNavigation: MapboxNavigation
42+
43+
@Before
44+
fun setUp() {
45+
runOnMainSync {
46+
mapboxNavigation = MapboxNavigationProvider.create(
47+
NavigationOptions.Builder(activity)
48+
.accessToken(getMapboxAccessTokenFromResources(activity))
49+
.build()
50+
)
51+
}
52+
}
53+
54+
@Test
55+
fun preview_route() = sdkTest {
56+
val routes = RoutesProvider.dc_very_short(activity).toNavigationRoutes()
57+
mapboxNavigation.startTripSession()
58+
val previewedRouteDeffer = async {
59+
mapboxNavigation.waitForPreviewRoute()
60+
}
61+
62+
mapboxNavigation.previewNavigationRoutes(routes)
63+
64+
val previewRouteUpdate = previewedRouteDeffer.await()
65+
assertEquals(routes, previewRouteUpdate.navigationRoutes)
66+
assertEquals(RoutesExtra.ROUTES_UPDATE_REASON_PREVIEW, previewRouteUpdate.reason)
67+
assertEquals(routes, mapboxNavigation.getPreviewedNavigationRoutes())
68+
assertEquals(emptyList<NavigationRoute>(), mapboxNavigation.getNavigationRoutes())
69+
assertIs<NavigationSessionState.FreeDrive>(mapboxNavigation.getNavigationSessionState())
70+
assertIs<NavigationSessionStateV2.RoutePreview>(mapboxNavigation.getNavigationSessionStateV2())
71+
}
72+
73+
@Test
74+
fun preview_route_with_alternative() = sdkTest {
75+
val routes = RoutesProvider.dc_short_with_alternative(activity).toNavigationRoutes()
76+
mapboxNavigation.startTripSession()
77+
val previewedRouteDeffer = async {
78+
mapboxNavigation.waitForPreviewRoute()
79+
}
80+
81+
mapboxNavigation.previewNavigationRoutes(routes)
82+
83+
val previewRouteUpdate = previewedRouteDeffer.await()
84+
val previewedRouteMetadata = mapboxNavigation.getAlternativeMetadataFor(
85+
previewRouteUpdate.navigationRoutes[1]
86+
)
87+
assertNotNull(previewedRouteMetadata)
88+
}
89+
90+
@Test
91+
fun start_active_guidance_after_preview() = sdkTest {
92+
val routes = RoutesProvider.dc_short_with_alternative(activity).toNavigationRoutes()
93+
mapboxNavigation.startTripSession()
94+
val previewedRouteDeferred = async {
95+
mapboxNavigation.waitForPreviewRoute()
96+
}
97+
mapboxNavigation.previewNavigationRoutes(routes)
98+
previewedRouteDeferred.await()
99+
val activeGuidanceRouteUpdateDefer = async {
100+
mapboxNavigation.waitForNewRoute()
101+
}
102+
103+
mapboxNavigation.setNavigationRoutes(mapboxNavigation.getPreviewedNavigationRoutes())
104+
105+
val activeGuidanceRouteUpdate = activeGuidanceRouteUpdateDefer.await()
106+
assertEquals(RoutesExtra.ROUTES_UPDATE_REASON_NEW, activeGuidanceRouteUpdate.reason)
107+
assertEquals(routes, activeGuidanceRouteUpdate.navigationRoutes)
108+
109+
assertIs<NavigationSessionState.ActiveGuidance>(mapboxNavigation.getNavigationSessionState())
110+
assertIs<NavigationSessionStateV2.ActiveGuidance>(mapboxNavigation.getNavigationSessionStateV2())
111+
}
112+
113+
@Test
114+
fun switch_to_free_drive_after_preview() = sdkTest {
115+
val routes = RoutesProvider.dc_very_short(activity).toNavigationRoutes()
116+
mapboxNavigation.startTripSession()
117+
val previewedRouteDeffer = async {
118+
mapboxNavigation.waitForPreviewRoute()
119+
}
120+
mapboxNavigation.previewNavigationRoutes(routes)
121+
previewedRouteDeffer.await()
122+
val freeDriveRoutesUpdateDeferred = async {
123+
mapboxNavigation.waitForRoutesCleanUp()
124+
}
125+
126+
mapboxNavigation.clearRoutes()
127+
128+
val freeDriveRoutesUpdate = freeDriveRoutesUpdateDeferred.await()
129+
assertEquals(emptyList<NavigationRoute>(), freeDriveRoutesUpdate.navigationRoutes)
130+
assertEquals(emptyList<NavigationRoute>(), mapboxNavigation.getNavigationRoutes())
131+
assertIs<NavigationSessionState.FreeDrive>(mapboxNavigation.getNavigationSessionState())
132+
assertIs<NavigationSessionStateV2.FreeDrive>(mapboxNavigation.getNavigationSessionStateV2())
133+
}
134+
}
135+
136+
private inline fun <reified T> assertIs(obj: Any) {
137+
assertTrue(
138+
"expected an instance of ${T::class.java.name}, but it is $obj (${obj.javaClass.name})",
139+
obj is T
140+
)
141+
}

instrumentation-tests/src/androidTest/java/com/mapbox/navigation/instrumentation_tests/utils/coroutines/TestUtils.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,18 +100,24 @@ suspend fun MapboxNavigation.setNavigationRoutesAndWaitForAlternativesUpdate(
100100
waitForAlternativeRoute()
101101
}
102102

103-
suspend fun MapboxNavigation.waitForNewRoute() {
103+
suspend fun MapboxNavigation.waitForNewRoute(): RoutesUpdatedResult =
104104
waitForRoutesUpdate(RoutesExtra.ROUTES_UPDATE_REASON_NEW)
105-
}
105+
106+
suspend fun MapboxNavigation.waitForRoutesCleanUp(): RoutesUpdatedResult =
107+
waitForRoutesUpdate(RoutesExtra.ROUTES_UPDATE_REASON_CLEAN_UP)
106108

107109
suspend fun MapboxNavigation.waitForAlternativeRoute() {
108110
waitForRoutesUpdate(RoutesExtra.ROUTES_UPDATE_REASON_ALTERNATIVE)
109111
}
110112

113+
suspend fun MapboxNavigation.waitForPreviewRoute(): RoutesUpdatedResult {
114+
return waitForRoutesUpdate(RoutesExtra.ROUTES_UPDATE_REASON_PREVIEW)
115+
}
116+
111117
private suspend fun MapboxNavigation.waitForRoutesUpdate(
112118
@RoutesExtra.RoutesUpdateReason reason: String
113-
) {
114-
routesUpdates()
119+
): RoutesUpdatedResult {
120+
return routesUpdates()
115121
.filter { it.reason == reason }
116122
.first()
117123
}

0 commit comments

Comments
 (0)