Skip to main content
GuidesAPI ReferenceExamples

Voice Instruction Simulated Navigation

Estimated reading time: 4 minutes

In this guide you will learn how to simulate navigation along a computed route rendered on an interactive map, from a departure position to a desired destination. The map is fully 3D, supporting pan, pinch-zoom, rotate and tilt. The navigation includes voice instructions in a language of your choice.

Setup

  1. Get your Magic Lane API key token: if you do not have a token, see the Getting Started guide
  2. Download the Maps & Navigation SDK for Android archive file
  3. Download the VoiceInstrRouteSimulation project archive file or clone the project with Git
  4. See the Configure Android Example guide

Run the example

In Android Studio, from the File menu, select Sync Project with Gradle Files

An android device should be connected via USB cable.
Press SHIFT+F10 to compile, install and run the example on the android device.

How it works

How it works

You can open the MainActivity.kt file to see how simulated navigation along a computed route with voice instructions works.

private val navigationService = NavigationService()

A NavigationService() is instantiated, which carries out both simulated navigation and real navigation.

private val navigationListener: NavigationListener = NavigationListener.create(
onNavigationStarted = { onNavigationStarted() },
onNavigationSound = { sound ->
SdkCall.execute {
SoundPlayingService.play(sound, playingListener, soundPreference)
}
},
canPlayNavigationSound = true,
postOnMain = true
)

The NavigationListener receives event updates during navigation such as when the destination is reached, or when the route to the desired destination has been recomputed, because a detour away from the original route was taken.

Besides the onNavigationStarted listener, the onNavigationSound listener is also instantiated, to receive the voice instructions for turns and other events along the route, including warnings, such as about speed cameras or exceeding the posted speed limit.

private val routingProgressListener = ProgressListener.create(
onStarted = {
progressBar.visibility = View.VISIBLE
},
onCompleted = { _, _ ->
progressBar.visibility = View.GONE
},
postOnMain = true
)

Define a listener to indicate when the route computation is completed, so real or simulated navigation (simulated in this case) can start.

private fun onNavigationStarted() = SdkCall.execute {
gemSurfaceView.mapView?.let { mapView ->
mapView.preferences?.enableCursor = false
navigationService.getNavigationRoute(navigationListener)?.let { route ->
mapView.presentRoute(route)
}
enableGPSButton()
mapView.followPosition()
}
}

When navigation is started, mapView.followPosition() causes the camera to follow the green arrow. If the user pans (moves) the map to another location, the camera no longer follows the green arrow.


private fun onNavigationStarted() = SdkCall.execute {
gemSurfaceView.mapView?.let { mapView ->
mapView.preferences?.enableCursor = false
navigationService.getNavigationRoute(navigationListener)?.let { route ->
mapView.presentRoute(route)
}
enableGPSButton()
mapView.followPosition()
}
}

enableGPSButton() causes a round purple button to appear in the lower right corner of the screen, whenever the simulation is active and the camera is not following the green arrow. If the user pushes this button, the followPosition() function is called, and thus the camera starts to follow the green arrow once again.

private fun startSimulation() = SdkCall.execute {
val waypoints = arrayListOf(
Landmark("Start", 48.526, 7.734),
Landmark("Destination", 41.645, -0.883)
)
navigationService.startSimulation(waypoints, navigationListener, routingProgressListener)
}

The starting, or departure point of the route is the first waypoint in a list of 2 or more Landmarks (2 in this case), each containing a name, latitude (in degrees) and longitude (in degrees). The destination point is the last waypoint in the list.

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
progressBar = findViewById(R.id.progressBar)
gemSurfaceView = findViewById(R.id.gem_surface)
followCursorButton = findViewById(R.id.followCursor)

SdkSettings.onMapDataReady = onMapDataReady@{ isReady ->
if (!isReady) return@onMapDataReady

SdkCall.execute {
contentStore = ContentStore()

val type = EContentType.HumanVoice
val countryCode = "IRL"
val onVoiceReady = { voiceFilePath: String ->
SdkSettings.setVoiceByPath(voiceFilePath)
startSimulation()
}
// check if already exists locally
contentStore?.getLocalContentList(type)?.let { localList ->
for (item in localList) {
if (item.countryCodes?.contains(countryCode) == true) {
onVoiceReady(item.filename!!)
return@execute // already exists
}
}
}
// download the voice
contentStore?.asyncGetStoreContentList(type, onCompleted =
{ result, _, _ ->
SdkCall.execute {
for (item in result) {
if (item.countryCodes?.contains(countryCode) == true) {
item.asyncDownload(onCompleted = { _, _ ->
SdkCall.execute {
onVoiceReady(item.filename!!)
}
})
break
}
}
}
})
}
}
}

The MainActivity overrides the onCreate() function which downloads the voice from the server to be used for the voice instructions during the simulated navigation.

Note the 3-letter ISO countrycode val countryCode = "IRL" to specify which voice to download.

A complete list of these country codes can be found here

Android Examples

Maps SDK for Android Examples can be downloaded or cloned with Git