Add a complete turn-by-turn experience
NOTE
This example is a part of the Navigation SDK Examples. You can find the values for all referenced resources in the res
directory. For example, see res/values/strings.xml
for R.string.*
references used in this example.
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"> <com.mapbox.maps.MapViewandroid:id="@+id/mapView"android:layout_width="0dp"android:layout_height="0dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /> <androidx.cardview.widget.CardViewandroid:id="@+id/tripProgressCard"android:layout_width="0dp"android:layout_height="wrap_content"android:visibility="invisible"app:cardElevation="8dp"app:cardUseCompatPadding="false"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"> <com.mapbox.navigation.ui.tripprogress.view.MapboxTripProgressViewandroid:id="@+id/tripProgressView"android:layout_width="match_parent"android:layout_height="wrap_content" /> <ImageViewandroid:id="@+id/stop"android:layout_width="48dp"android:layout_height="48dp"android:layout_gravity="end|center_vertical"android:layout_marginEnd="12dp"app:srcCompat="@android:drawable/ic_delete" /></androidx.cardview.widget.CardView> <com.mapbox.navigation.ui.maneuver.view.MapboxManeuverViewandroid:id="@+id/maneuverView"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_margin="4dp"android:visibility="invisible"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /> <com.mapbox.navigation.ui.voice.view.MapboxSoundButtonandroid:id="@+id/soundButton"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="8dp"android:layout_marginEnd="16dp"android:visibility="invisible"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toBottomOf="@id/maneuverView" /> <com.mapbox.navigation.ui.maps.camera.view.MapboxRouteOverviewButtonandroid:id="@+id/routeOverview"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="8dp"android:layout_marginEnd="16dp"android:visibility="invisible"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toBottomOf="@id/soundButton" /> <com.mapbox.navigation.ui.maps.camera.view.MapboxRecenterButtonandroid:id="@+id/recenter"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="8dp"android:layout_marginEnd="16dp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toBottomOf="@id/routeOverview" /> </androidx.constraintlayout.widget.ConstraintLayout>
package com.mapbox.navigation.examples.standalone.turnbyturn import android.annotation.SuppressLintimport android.content.res.Configurationimport android.content.res.Resourcesimport android.location.Locationimport android.os.Bundleimport android.view.Viewimport android.widget.Toastimport androidx.appcompat.app.AppCompatActivityimport androidx.core.content.ContextCompatimport com.mapbox.api.directions.v5.models.Bearingimport com.mapbox.api.directions.v5.models.RouteOptionsimport com.mapbox.bindgen.Expectedimport com.mapbox.geojson.Pointimport com.mapbox.maps.EdgeInsetsimport com.mapbox.maps.plugin.LocationPuck2Dimport com.mapbox.maps.plugin.animation.cameraimport com.mapbox.maps.plugin.gestures.gesturesimport com.mapbox.maps.plugin.locationcomponent.locationimport com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPIimport com.mapbox.navigation.base.TimeFormatimport com.mapbox.navigation.base.extensions.applyDefaultNavigationOptionsimport com.mapbox.navigation.base.extensions.applyLanguageAndVoiceUnitOptionsimport com.mapbox.navigation.base.formatter.DistanceFormatterOptionsimport com.mapbox.navigation.base.options.NavigationOptionsimport com.mapbox.navigation.base.route.NavigationRouteimport com.mapbox.navigation.base.route.NavigationRouterCallbackimport com.mapbox.navigation.base.route.RouterFailureimport com.mapbox.navigation.base.route.RouterOriginimport com.mapbox.navigation.core.MapboxNavigationimport com.mapbox.navigation.core.directions.session.RoutesObserverimport com.mapbox.navigation.core.formatter.MapboxDistanceFormatterimport com.mapbox.navigation.core.lifecycle.MapboxNavigationAppimport com.mapbox.navigation.core.lifecycle.MapboxNavigationObserverimport com.mapbox.navigation.core.lifecycle.requireMapboxNavigationimport com.mapbox.navigation.core.replay.MapboxReplayerimport com.mapbox.navigation.core.replay.ReplayLocationEngineimport com.mapbox.navigation.core.replay.route.ReplayProgressObserverimport com.mapbox.navigation.core.replay.route.ReplayRouteMapperimport com.mapbox.navigation.core.trip.session.LocationMatcherResultimport com.mapbox.navigation.core.trip.session.LocationObserverimport com.mapbox.navigation.core.trip.session.RouteProgressObserverimport com.mapbox.navigation.core.trip.session.VoiceInstructionsObserverimport com.mapbox.navigation.examples.Rimport com.mapbox.navigation.examples.databinding.MapboxActivityTurnByTurnExperienceBindingimport com.mapbox.navigation.ui.base.util.MapboxNavigationConsumerimport com.mapbox.navigation.ui.maneuver.api.MapboxManeuverApiimport com.mapbox.navigation.ui.maneuver.view.MapboxManeuverViewimport com.mapbox.navigation.ui.maps.NavigationStylesimport com.mapbox.navigation.ui.maps.camera.NavigationCameraimport com.mapbox.navigation.ui.maps.camera.data.MapboxNavigationViewportDataSourceimport com.mapbox.navigation.ui.maps.camera.lifecycle.NavigationBasicGesturesHandlerimport com.mapbox.navigation.ui.maps.camera.state.NavigationCameraStateimport com.mapbox.navigation.ui.maps.camera.transition.NavigationCameraTransitionOptionsimport com.mapbox.navigation.ui.maps.location.NavigationLocationProviderimport com.mapbox.navigation.ui.maps.route.arrow.api.MapboxRouteArrowApiimport com.mapbox.navigation.ui.maps.route.arrow.api.MapboxRouteArrowViewimport com.mapbox.navigation.ui.maps.route.arrow.model.RouteArrowOptionsimport com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApiimport com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineViewimport com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineOptionsimport com.mapbox.navigation.ui.tripprogress.api.MapboxTripProgressApiimport com.mapbox.navigation.ui.tripprogress.model.DistanceRemainingFormatterimport com.mapbox.navigation.ui.tripprogress.model.EstimatedTimeToArrivalFormatterimport com.mapbox.navigation.ui.tripprogress.model.PercentDistanceTraveledFormatterimport com.mapbox.navigation.ui.tripprogress.model.TimeRemainingFormatterimport com.mapbox.navigation.ui.tripprogress.model.TripProgressUpdateFormatterimport com.mapbox.navigation.ui.tripprogress.view.MapboxTripProgressViewimport com.mapbox.navigation.ui.voice.api.MapboxSpeechApiimport com.mapbox.navigation.ui.voice.api.MapboxVoiceInstructionsPlayerimport com.mapbox.navigation.ui.voice.model.SpeechAnnouncementimport com.mapbox.navigation.ui.voice.model.SpeechErrorimport com.mapbox.navigation.ui.voice.model.SpeechValueimport com.mapbox.navigation.ui.voice.model.SpeechVolumeimport java.util.Dateimport java.util.Locale /*** This example demonstrates a basic turn-by-turn navigation experience by putting together some UI elements to showcase* navigation camera transitions, guidance instructions banners and playback, and progress along the route.** Before running the example make sure you have put your access_token in the correct place* inside [app/src/main/res/values/mapbox_access_token.xml]. If not present then add this file* at the location mentioned above and add the following content to it** <?xml version="1.0" encoding="utf-8"?>* <resources xmlns:tools="http://schemas.android.com/tools">* <string name="mapbox_access_token"><PUT_YOUR_ACCESS_TOKEN_HERE></string>* </resources>** The example assumes that you have granted location permissions and does not enforce it. However,* the permission is essential for proper functioning of this example. The example also uses replay* location engine to facilitate navigation without actually physically moving.** How to use this example:* - You can long-click the map to select a destination.* - The guidance will start to the selected destination while simulating location updates.* You can disable simulation by commenting out the [replayLocationEngine] setter in [NavigationOptions].* Then, the device's real location will be used.* - At any point in time you can finish guidance or select a new destination.* - You can use buttons to mute/unmute voice instructions, recenter the camera, or show the route overview.*/@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)class TurnByTurnExperienceActivity : AppCompatActivity() { private companion object {private const val BUTTON_ANIMATION_DURATION = 1500L} /*** Debug tool used to play, pause and seek route progress events that can be used to produce mocked location updates along the route.*/private val mapboxReplayer = MapboxReplayer() /*** Debug tool that mocks location updates with an input from the [mapboxReplayer].*/private val replayLocationEngine = ReplayLocationEngine(mapboxReplayer) /*** Debug observer that makes sure the replayer has always an up-to-date information to generate mock updates.*/private val replayProgressObserver = ReplayProgressObserver(mapboxReplayer) /*** Bindings to the example layout.*/private lateinit var binding: MapboxActivityTurnByTurnExperienceBinding /*** Used to execute camera transitions based on the data generated by the [viewportDataSource].* This includes transitions from route overview to route following and continuously updating the camera as the location changes.*/private lateinit var navigationCamera: NavigationCamera /*** Produces the camera frames based on the location and routing data for the [navigationCamera] to execute.*/private lateinit var viewportDataSource: MapboxNavigationViewportDataSource /** Below are generated camera padding values to ensure that the route fits well on screen while* other elements are overlaid on top of the map (including instruction view, buttons, etc.)*/private val pixelDensity = Resources.getSystem().displayMetrics.densityprivate val overviewPadding: EdgeInsets by lazy {EdgeInsets(140.0 * pixelDensity,40.0 * pixelDensity,120.0 * pixelDensity,40.0 * pixelDensity)}private val landscapeOverviewPadding: EdgeInsets by lazy {EdgeInsets(30.0 * pixelDensity,380.0 * pixelDensity,110.0 * pixelDensity,20.0 * pixelDensity)}private val followingPadding: EdgeInsets by lazy {EdgeInsets(180.0 * pixelDensity,40.0 * pixelDensity,150.0 * pixelDensity,40.0 * pixelDensity)}private val landscapeFollowingPadding: EdgeInsets by lazy {EdgeInsets(30.0 * pixelDensity,380.0 * pixelDensity,110.0 * pixelDensity,40.0 * pixelDensity)} /*** Generates updates for the [MapboxManeuverView] to display the upcoming maneuver instructions* and remaining distance to the maneuver point.*/private lateinit var maneuverApi: MapboxManeuverApi /*** Generates updates for the [MapboxTripProgressView] that include remaining time and distance to the destination.*/private lateinit var tripProgressApi: MapboxTripProgressApi /*** Generates updates for the [routeLineView] with the geometries and properties of the routes that should be drawn on the map.*/private lateinit var routeLineApi: MapboxRouteLineApi /*** Draws route lines on the map based on the data from the [routeLineApi]*/private lateinit var routeLineView: MapboxRouteLineView /*** Generates updates for the [routeArrowView] with the geometries and properties of maneuver arrows that should be drawn on the map.*/private val routeArrowApi: MapboxRouteArrowApi = MapboxRouteArrowApi() /*** Draws maneuver arrows on the map based on the data [routeArrowApi].*/private lateinit var routeArrowView: MapboxRouteArrowView /*** Stores and updates the state of whether the voice instructions should be played as they come or muted.*/private var isVoiceInstructionsMuted = falseset(value) {field = valueif (value) {binding.soundButton.muteAndExtend(BUTTON_ANIMATION_DURATION)voiceInstructionsPlayer.volume(SpeechVolume(0f))} else {binding.soundButton.unmuteAndExtend(BUTTON_ANIMATION_DURATION)voiceInstructionsPlayer.volume(SpeechVolume(1f))}} /*** Extracts message that should be communicated to the driver about the upcoming maneuver.* When possible, downloads a synthesized audio file that can be played back to the driver.*/private lateinit var speechApi: MapboxSpeechApi /*** Plays the synthesized audio files with upcoming maneuver instructions* or uses an on-device Text-To-Speech engine to communicate the message to the driver.* NOTE: do not use lazy initialization for this class since it takes some time to initialize* the system services required for on-device speech synthesis. With lazy initialization* there is a high risk that said services will not be available when the first instruction* has to be played. [MapboxVoiceInstructionsPlayer] should be instantiated in* `Activity#onCreate`.*/private lateinit var voiceInstructionsPlayer: MapboxVoiceInstructionsPlayer /*** Observes when a new voice instruction should be played.*/private val voiceInstructionsObserver = VoiceInstructionsObserver { voiceInstructions ->speechApi.generate(voiceInstructions, speechCallback)} /*** Based on whether the synthesized audio file is available, the callback plays the file* or uses the fall back which is played back using the on-device Text-To-Speech engine.*/private val speechCallback =MapboxNavigationConsumer<Expected<SpeechError, SpeechValue>> { expected ->expected.fold({ error ->// play the instruction via fallback text-to-speech enginevoiceInstructionsPlayer.play(error.fallback,voiceInstructionsPlayerCallback)},{ value ->// play the sound file from the external generatorvoiceInstructionsPlayer.play(value.announcement,voiceInstructionsPlayerCallback)})} /*** When a synthesized audio file was downloaded, this callback cleans up the disk after it was played.*/private val voiceInstructionsPlayerCallback =MapboxNavigationConsumer<SpeechAnnouncement> { value ->// remove already consumed file to free-up spacespeechApi.clean(value)} /*** [NavigationLocationProvider] is a utility class that helps to provide location updates generated by the Navigation SDK* to the Maps SDK in order to update the user location indicator on the map.*/private val navigationLocationProvider = NavigationLocationProvider() /*** Gets notified with location updates.** Exposes raw updates coming directly from the location services* and the updates enhanced by the Navigation SDK (cleaned up and matched to the road).*/private val locationObserver = object : LocationObserver {var firstLocationUpdateReceived = false override fun onNewRawLocation(rawLocation: Location) {// not handled} override fun onNewLocationMatcherResult(locationMatcherResult: LocationMatcherResult) {val enhancedLocation = locationMatcherResult.enhancedLocation// update location puck's position on the mapnavigationLocationProvider.changePosition(location = enhancedLocation,keyPoints = locationMatcherResult.keyPoints,) // update camera position to account for new locationviewportDataSource.onLocationChanged(enhancedLocation)viewportDataSource.evaluate() // if this is the first location update the activity has received,// it's best to immediately move the camera to the current user locationif (!firstLocationUpdateReceived) {firstLocationUpdateReceived = truenavigationCamera.requestNavigationCameraToOverview(stateTransitionOptions = NavigationCameraTransitionOptions.Builder().maxDuration(0) // instant transition.build())}}} /*** Gets notified with progress along the currently active route.*/private val routeProgressObserver = RouteProgressObserver { routeProgress ->// update the camera position to account for the progressed fragment of the routeviewportDataSource.onRouteProgressChanged(routeProgress)viewportDataSource.evaluate() // draw the upcoming maneuver arrow on the mapval style = binding.mapView.getMapboxMap().getStyle()if (style != null) {val maneuverArrowResult = routeArrowApi.addUpcomingManeuverArrow(routeProgress)routeArrowView.renderManeuverUpdate(style, maneuverArrowResult)} // update top banner with maneuver instructionsval maneuvers = maneuverApi.getManeuvers(routeProgress)maneuvers.fold({ error ->Toast.makeText(this@TurnByTurnExperienceActivity,error.errorMessage,Toast.LENGTH_SHORT).show()},{binding.maneuverView.visibility = View.VISIBLEbinding.maneuverView.renderManeuvers(maneuvers)}) // update bottom trip progress summarybinding.tripProgressView.render(tripProgressApi.getTripProgress(routeProgress))} /*** Gets notified whenever the tracked routes change.** A change can mean:* - routes get changed with [MapboxNavigation.setRoutes]* - routes annotations get refreshed (for example, congestion annotation that indicate the live traffic along the route)* - driver got off route and a reroute was executed*/private val routesObserver = RoutesObserver { routeUpdateResult ->if (routeUpdateResult.navigationRoutes.isNotEmpty()) {// generate route geometries asynchronously and render themrouteLineApi.setNavigationRoutes(routeUpdateResult.navigationRoutes) { value ->binding.mapView.getMapboxMap().getStyle()?.apply {routeLineView.renderRouteDrawData(this, value)}} // update the camera position to account for the new routeviewportDataSource.onRouteChanged(routeUpdateResult.navigationRoutes.first())viewportDataSource.evaluate()} else {// remove the route line and route arrow from the mapval style = binding.mapView.getMapboxMap().getStyle()if (style != null) {routeLineApi.clearRouteLine { value ->routeLineView.renderClearRouteLineValue(style,value)}routeArrowView.render(style, routeArrowApi.clearArrows())} // remove the route reference from camera position evaluationsviewportDataSource.clearRouteData()viewportDataSource.evaluate()}} private val mapboxNavigation: MapboxNavigation by requireMapboxNavigation(onResumedObserver = object : MapboxNavigationObserver {@SuppressLint("MissingPermission")override fun onAttached(mapboxNavigation: MapboxNavigation) {mapboxNavigation.registerRoutesObserver(routesObserver)mapboxNavigation.registerLocationObserver(locationObserver)mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)mapboxNavigation.registerRouteProgressObserver(replayProgressObserver)mapboxNavigation.registerVoiceInstructionsObserver(voiceInstructionsObserver)// start the trip session to being receiving location updates in free drive// and later when a route is set also receiving route progress updatesmapboxNavigation.startTripSession()} override fun onDetached(mapboxNavigation: MapboxNavigation) {mapboxNavigation.unregisterRoutesObserver(routesObserver)mapboxNavigation.unregisterLocationObserver(locationObserver)mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver)mapboxNavigation.unregisterRouteProgressObserver(replayProgressObserver)mapboxNavigation.unregisterVoiceInstructionsObserver(voiceInstructionsObserver)}},onInitialize = this::initNavigation) @SuppressLint("MissingPermission")override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = MapboxActivityTurnByTurnExperienceBinding.inflate(layoutInflater)setContentView(binding.root) // initialize Navigation CameraviewportDataSource = MapboxNavigationViewportDataSource(binding.mapView.getMapboxMap())navigationCamera = NavigationCamera(binding.mapView.getMapboxMap(),binding.mapView.camera,viewportDataSource)// set the animations lifecycle listener to ensure the NavigationCamera stops// automatically following the user location when the map is interacted withbinding.mapView.camera.addCameraAnimationsLifecycleListener(NavigationBasicGesturesHandler(navigationCamera))navigationCamera.registerNavigationCameraStateChangeObserver { navigationCameraState ->// shows/hide the recenter button depending on the camera statewhen (navigationCameraState) {NavigationCameraState.TRANSITION_TO_FOLLOWING,NavigationCameraState.FOLLOWING -> binding.recenter.visibility = View.INVISIBLENavigationCameraState.TRANSITION_TO_OVERVIEW,NavigationCameraState.OVERVIEW,NavigationCameraState.IDLE -> binding.recenter.visibility = View.VISIBLE}}// set the padding values depending on screen orientation and visible view layoutif (this.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {viewportDataSource.overviewPadding = landscapeOverviewPadding} else {viewportDataSource.overviewPadding = overviewPadding}if (this.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {viewportDataSource.followingPadding = landscapeFollowingPadding} else {viewportDataSource.followingPadding = followingPadding} // make sure to use the same DistanceFormatterOptions across different featuresval distanceFormatterOptions = DistanceFormatterOptions.Builder(this).build() // initialize maneuver api that feeds the data to the top banner maneuver viewmaneuverApi = MapboxManeuverApi(MapboxDistanceFormatter(distanceFormatterOptions)) // initialize bottom progress viewtripProgressApi = MapboxTripProgressApi(TripProgressUpdateFormatter.Builder(this).distanceRemainingFormatter(DistanceRemainingFormatter(distanceFormatterOptions)).timeRemainingFormatter(TimeRemainingFormatter(this)).percentRouteTraveledFormatter(PercentDistanceTraveledFormatter()).estimatedTimeToArrivalFormatter(EstimatedTimeToArrivalFormatter(this, TimeFormat.NONE_SPECIFIED)).build()) // initialize voice instructions api and the voice instruction playerspeechApi = MapboxSpeechApi(this,getString(R.string.mapbox_access_token),Locale.US.language)voiceInstructionsPlayer = MapboxVoiceInstructionsPlayer(this,getString(R.string.mapbox_access_token),Locale.US.language) // initialize route line, the withRouteLineBelowLayerId is specified to place// the route line below road labels layer on the map// the value of this option will depend on the style that you are using// and under which layer the route line should be placed on the map layers stackval mapboxRouteLineOptions = MapboxRouteLineOptions.Builder(this).withRouteLineBelowLayerId("road-label-navigation").build()routeLineApi = MapboxRouteLineApi(mapboxRouteLineOptions)routeLineView = MapboxRouteLineView(mapboxRouteLineOptions) // initialize maneuver arrow view to draw arrows on the mapval routeArrowOptions = RouteArrowOptions.Builder(this).build()routeArrowView = MapboxRouteArrowView(routeArrowOptions) // load map stylebinding.mapView.getMapboxMap().loadStyleUri(NavigationStyles.NAVIGATION_DAY_STYLE) {// add long click listener that search for a route to the clicked destinationbinding.mapView.gestures.addOnMapLongClickListener { point ->findRoute(point)true}} // initialize view interactionsbinding.stop.setOnClickListener {clearRouteAndStopNavigation()}binding.recenter.setOnClickListener {navigationCamera.requestNavigationCameraToFollowing()binding.routeOverview.showTextAndExtend(BUTTON_ANIMATION_DURATION)}binding.routeOverview.setOnClickListener {navigationCamera.requestNavigationCameraToOverview()binding.recenter.showTextAndExtend(BUTTON_ANIMATION_DURATION)}binding.soundButton.setOnClickListener {// mute/unmute voice instructionsisVoiceInstructionsMuted = !isVoiceInstructionsMuted} // set initial sounds button statebinding.soundButton.unmute()} override fun onDestroy() {super.onDestroy()mapboxReplayer.finish()maneuverApi.cancel()routeLineApi.cancel()routeLineView.cancel()speechApi.cancel()voiceInstructionsPlayer.shutdown()} private fun initNavigation() {MapboxNavigationApp.setup(NavigationOptions.Builder(this).accessToken(getString(R.string.mapbox_access_token))// comment out the location engine setting block to disable simulation.locationEngine(replayLocationEngine).build()) // initialize location puckbinding.mapView.location.apply {setLocationProvider(navigationLocationProvider)this.locationPuck = LocationPuck2D(bearingImage = ContextCompat.getDrawable(this@TurnByTurnExperienceActivity,R.drawable.mapbox_navigation_puck_icon))enabled = true} replayOriginLocation()} private fun replayOriginLocation() {mapboxReplayer.pushEvents(listOf(ReplayRouteMapper.mapToUpdateLocation(Date().time.toDouble(),Point.fromLngLat(-122.39726512303575, 37.785128345296805))))mapboxReplayer.playFirstLocation()mapboxReplayer.playbackSpeed(3.0)} private fun findRoute(destination: Point) {val originLocation = navigationLocationProvider.lastLocationval originPoint = originLocation?.let {Point.fromLngLat(it.longitude, it.latitude)} ?: return // execute a route request// it's recommended to use the// applyDefaultNavigationOptions and applyLanguageAndVoiceUnitOptions// that make sure the route request is optimized// to allow for support of all of the Navigation SDK featuresmapboxNavigation.requestRoutes(RouteOptions.builder().applyDefaultNavigationOptions().applyLanguageAndVoiceUnitOptions(this).coordinatesList(listOf(originPoint, destination))// provide the bearing for the origin of the request to ensure// that the returned route faces in the direction of the current user movement.bearingsList(listOf(Bearing.builder().angle(originLocation.bearing.toDouble()).degrees(45.0).build(),null)).layersList(listOf(mapboxNavigation.getZLevel(), null)).build(),object : NavigationRouterCallback {override fun onCanceled(routeOptions: RouteOptions, routerOrigin: RouterOrigin) {// no impl} override fun onFailure(reasons: List<RouterFailure>, routeOptions: RouteOptions) {// no impl} override fun onRoutesReady(routes: List<NavigationRoute>,routerOrigin: RouterOrigin) {setRouteAndStartNavigation(routes)}})} private fun setRouteAndStartNavigation(routes: List<NavigationRoute>) {// set routes, where the first route in the list is the primary route that// will be used for active guidancemapboxNavigation.setNavigationRoutes(routes) // show UI elementsbinding.soundButton.visibility = View.VISIBLEbinding.routeOverview.visibility = View.VISIBLEbinding.tripProgressCard.visibility = View.VISIBLE // move the camera to overview when new route is availablenavigationCamera.requestNavigationCameraToOverview()} private fun clearRouteAndStopNavigation() {// clearmapboxNavigation.setNavigationRoutes(listOf()) // stop simulationmapboxReplayer.stop() // hide UI elementsbinding.soundButton.visibility = View.INVISIBLEbinding.maneuverView.visibility = View.INVISIBLEbinding.routeOverview.visibility = View.INVISIBLEbinding.tripProgressCard.visibility = View.INVISIBLE}}