Navigation use case
Navigation SDK for Android is only available upon request. Contact us to get started.
This tutorial shows how to build a simple navigation application using the TomTom Navigation
SDK for Android. The app uses the built-in UI components. However, you can build custom components and integrate them with the SDK.
The application displays a map and shows the user’s location. After the user selects a destination with a long click, the app plans a route and draws it on the map. Navigation is started once the user taps on the route.
Getting started
- Install Android Studio if you don’t already have it.
- Create a new project or open an existing one. Make sure that the minimum SDK API level is set to at least 21 (Android 5.0 "Lollipop") and that the compile SDK API level is set to 31.
- Add the
packagingOptions
.1android {2 ...3 packagingOptions {4 jniLibs.pickFirsts.add("lib/**/libc++_shared.so")5 }6} - Because the repository for Navigation SDK is private, you will need to contact us to get access.
- Once you have obtained access, go to repositories.tomtom.com and log in with your account. Expand the user menu in the top-right corner, and select "Edit profile" → "Generate an Identity Token". Copy your token and put it, together with your login, in the
settings.gradle
file of your project, replacing the repositoryUsername and repositoryToken placeholders.1dependencyResolutionManagement {2 repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)3 repositories {4 google()5 mavenCentral()6 maven {7 credentials {8 username = repositoryUsername9 password = repositoryToken10 }11 url = uri("https://repositories.tomtom.com/artifactory/maven")12 }13 }14} - In the
app/build.gradle
file, add dependencies to the Map Display, Routing, Location, and Navigation modules.1dependencies {2 def version = "0.3.1617"3 implementation "com.tomtom.sdk.maps:map-display:$version"4 implementation "com.tomtom.sdk.routing:route-planner-online:$version"5 implementation "com.tomtom.sdk.location:provider-android:$version"6 implementation "com.tomtom.sdk.location:provider-simulation:$version"7 implementation "com.tomtom.sdk.location:provider-map-matched:$version"8 implementation "com.tomtom.sdk.navigation:navigation-online:$version"9 implementation "com.tomtom.sdk.navigation:ui:$version"10} - Add the appropriate TomTom API key. If you don’t have an API Key, go to How to get a TomTom API Key to learn how to create one.
Displaying a map
Once the project is set up with the appropriate dependencies, you can initialize the map. To initialize a map, prepare the FragmentContainerView
for the map. The map is displayed within this layout.
1<androidx.fragment.app.FragmentContainerView2 android:id="@+id/map_container"3 android:layout_width="match_parent"4 android:layout_height="match_parent" />
MapOptions
is required to initialize the map.- Use
MapFragment
to display a map. - Optional configuration: You can further configure the map by setting various properties of the
MapOptions
object. You can learn more in the Map Configuration guide. - The last step is adding the
MapFragment
to the previously created container.
Any interaction with the map, such as adding a marker or drawing a route, is made via the TomTomMap
object. Since map initialization can take a while, retrieving the TomTomMap
object has to be done asynchronously. Keep the instance of it for further actions.
1private fun initMap() {2 val mapOptions = MapOptions(mapKey = "YOUR_MAP_API_KEY")3 mapFragment = MapFragment.newInstance(mapOptions)4 supportFragmentManager.beginTransaction()5 .replace(R.id.map_container, mapFragment)6 .commit()7 mapFragment.getMapAsync { map ->8 tomTomMap = map11 }12}

Showing user location
Showing the user’s location is crucial in a navigation application. To do this, the application must use the device’s location services, which requires the appropriate permissions. The Android system requires the user to grant permissions for ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION.
On devices that run Android 6.0 or higher, you must request permissions at runtime. Learn how to grant location permissions in the Android Request location permissions document.
The TomTom SDK provides a LocationProvider
interface that is used between different modules to get location updates. This tutorial uses the AndroidLocationProvider
. Under the hood, the engine uses Android’s system location services. NOTE: to obtain location updates, the LocationProvider.enable()
method must be called. To learn more about the LocationProvider
, consult the Location quickstart guide.
1private fun initLocationProvider() {2 locationProvider = AndroidLocationProvider(context = this)3}
The LocationProvider
itself only reports location changes. It does not interact internally with the map or navigation. Therefore, to show the user’s location on the map you have to set the LocationProvider
to the TomTomMap
. You also have to manually enable the location indicator. It can be configured using the LocationMarkerOptions
class. Read more about user location on the map in the Showing User Location document.
1private fun showUserLocation() {2 locationProvider.enable()3 tomTomMap.setLocationProvider(locationProvider)4 val locationMarker = LocationMarkerOptions(type = LocationMarkerOptions.Type.Pointer)5 tomTomMap.enableLocationMarker(locationMarker)6}

Generating a route
This section describes how to calculate a route between two locations and display it on the map. You can find more details on adjusting planning criteria and accommodating vehicle profiles in the routing documentation.
In this tutorial on generating a route, the origin is the user’s location and the destination is determined by the user selecting a location on the map. To mark the destination on the map, add the MapLongClickListener
event handler to the map view. The method removes all polygons, circles, routes, and markers that were previously added to the map. It then creates a route between the user’s location and the selected location. The method needs to return a boolean value when the callback is consumed.
1private val mapLongClickListener = MapLongClickListener { geoPoint ->2 clearMap()3 calculateRouteTo(geoPoint)4 true5}67private fun setUpMapListeners() {8 tomTomMap.addMapLongClickListener(mapLongClickListener)9}
Make sure to add listeners when the map instance is ready to be used.
1mapFragment.getMapAsync { map ->2 tomTomMap = map3 enableUserLocation()4 setUpMapListeners()5}
see full method
1 private fun initMap() {2 val mapOptions = MapOptions(mapKey = "YOUR_MAP_API_KEY")3 mapFragment = MapFragment.newInstance(mapOptions)4 supportFragmentManager.beginTransaction()5 .replace(R.id.map_container, mapFragment)6 .commit()7 mapFragment.getMapAsync { map ->8 tomTomMap = map9 enableUserLocation()10 setUpMapListeners()11 }12 }
The entry point for the routing service is the Routing API
interface. To initialize it, use the default TomTom implementation based on TomTom’s Routing API
.
1private fun initRouting() {2 routePlanner =3 OnlineRoutePlanner.create(context = this, apiKey = "YOUR_ROUTING_API_KEY")4}
You can plan a route using RoutePlanningOptions
and handle the planning result with RoutePlanningCallback
:
routePlanner.planRoute(routePlanningOptions, routePlanningCallback)
see full method
1 private fun calculateRouteTo(destination: GeoPoint) {2 val userLocation =3 tomTomMap.currentLocation?.position ?: return4 val itinerary = Itinerary(origin = userLocation, destination = destination)5 routePlanningOptions = RoutePlanningOptions(6 itinerary = itinerary,7 guidanceOptions = GuidanceOptions(8 instructionType = InstructionType.Text,9 phoneticsType = InstructionPhoneticsType.Ipa,10 announcementPoints = AnnouncementPoints.All,11 extendedSections = ExtendedSections.All,12 progressPoints = ProgressPoints.All13 ),14 vehicle = Vehicle.Car()15 )16 routePlanner.planRoute(routePlanningOptions, routePlanningCallback)17 }
For a better user experience during navigation, set the following guidance parameters in RoutePlanningOptions
:
InstructionType
- This indicates that the routing result has to contain guidance instructions.InstructionPhoneticsType
- This specifies whether to include phonetic transcriptions in the response.AnnouncementPoints
- When this parameter is specified, the instruction in the response includes up to three additional fine-grained announcement points, each with its own location, maneuver type, and distance to the instruction point.ExtendedSections
- This specifies whether to include extended guidance sections in the response, such as sections of type road shield, lane, and speed limit.ProgressPoints
- This specifies whether to include progress points in the response.
1routePlanningOptions = RoutePlanningOptions(2 itinerary = itinerary,3 guidanceOptions = GuidanceOptions(4 instructionType = InstructionType.Text,5 phoneticsType = InstructionPhoneticsType.Ipa,6 announcementPoints = AnnouncementPoints.All,7 extendedSections = ExtendedSections.All,8 progressPoints = ProgressPoints.All9 ),10 vehicle = Vehicle.Car()11)
The RoutePlanningCallback
itself has two methods. The first method is triggered if the request fails. The second method returns RoutePlanningResponse
containing the routing results. This tutorial draws the first retrieved route on the map, using the RouteOptions
class. You can show the overview of the added routes using the TomTomMap.zoomToRoutes(Int)
method. Note that its padding parameter is expressed in pixels. You can read more about adding a route to the map in Route Planning and Driving document.
1private val routePlanningCallback = object : RoutePlanningCallback {2 override fun onSuccess(result: RoutePlanningResponse) {3 route = result.routes.first()4 drawRoute(route!!)5 }67 override fun onFailure(failure: RoutingFailure) {8 Toast.makeText(this@MainActivity, failure.message, Toast.LENGTH_SHORT).show()9 }1011 override fun onRoutePlanned(route: Route) = Unit12}13private fun drawRoute(route: Route) {14 val instructions = route.mapInstructions()15 val routeOptions = RouteOptions(16 geometry = route.geometry,17 destinationMarkerVisible = true,18 departureMarkerVisible = true,19 instructions = instructions,20 routeOffset = route.routePoints.map { it.routeOffset }21 )22 tomTomMap.addRoute(routeOptions)23 tomTomMap.zoomToRoutes(ZOOM_TO_ROUTE_PADDING)24}25companion object {26 private const val ZOOM_TO_ROUTE_PADDING = 10027}
For the navigation use case, the instructions can be drawn on the route in form of arrows that indicate maneuvers. To do this, map the Instruction
object provided by routing to the Instruction
object used by the map. Note that during navigation, you need to update the progress property of the drawn route to display the next instructions.
1private fun Route.mapInstructions(): List<Instruction> {2 val routeInstructions = legs.flatMap { routeLeg -> routeLeg.instructions }3 return routeInstructions.map {4 Instruction(5 routeOffset = it.routeOffset,6 combineWithNext = it.combineWithNext7 )8 }9}

Starting navigation
This tutorial uses the built-in navigation UI and the location simulation engine to add turn-by-turn experience to your application. Using the built-in UI, the application will display upcoming manoeuvres, remaining distance, estimated time of arrival (ETA), current speed, and speed limit information. Read more about it in the Turn-by-turn navigation guide. It can be used with the provided user interface components or your custom ones. This tutorial uses the default Navigation UI in a form of the NavigationFragment
.
To use navigation in the application, start by /android/navigation/documentation/guides/quickstart#_navigation_configurationcreating the TomTomNavigation
object.
1@OptIn(ExperimentalOnlineNavigationFactory::class)2private fun initNavigation() {3 tomTomNavigation = TomTomNavigationFactory.createOnlineNavigation(4 context = this,5 apiKey = "YOUR_NAVIGATION_API_KEY",6 locationProvider = locationProvider,7 routePlanner = routePlanner8 )9}
Next, add the NavigationFragment
to display the UI navigation information.
Disposal of
TomTom Navigation
is not handled by theNavigationFragment
. You have to callTomTomNavigation.close()
on your own once the navigation is no longer needed.
1<androidx.fragment.app.FragmentContainerView2 android:id="@+id/navigation_fragment_container"3 android:layout_width="match_parent"4 android:layout_height="wrap_content"5 app:layout_constraintBottom_toBottomOf="@+id/map_container" />
1private fun initNavigationFragment() {2 val navigationUiOptions = NavigationUiOptions(3 keepInBackground = true4 )5 navigationFragment = NavigationFragment.newInstance(navigationUiOptions)6 supportFragmentManager.beginTransaction()7 .add(R.id.navigation_fragment_container, navigationFragment)8 .commitNow()9}
Start navigation by passing the Route
object along which the navigation will be done, and RoutePlanningOptions
used during the route planning. Note that you have to set the previously-created TomTomNavigation
object to the NavigationFragment
before using it.
1private fun startNavigation(route: Route) {2 initNavigationFragment()3 navigationFragment.setTomTomNavigation(tomTomNavigation)4 val routePlan = RoutePlan(route, routePlanningOptions)5 navigationFragment.startNavigation(routePlan)8}
Handle the updates to the navigation states using the NavigationListener
:
- Use
CameraChangeListener
to observe camera tracking mode and detect if the camera is locked on the chevron. If the user starts to move the camera, it will change and you can adjust the UI to suit.1private val cameraChangeListener by lazy {2 CameraChangeListener {3 val cameraTrackingMode = tomTomMap.cameraTrackingMode4 if (cameraTrackingMode == CameraTrackingMode.FollowRoute) {5 navigationFragment.navigationView.showSpeedView()6 } else {7 navigationFragment.navigationView.hideSpeedView()8 }9 }10} - Use the
SimulationLocationProvider
for testing purposes.1private fun setSimulationLocationProviderToNavigation(route: Route) {2 val routeGeoLocations = route.geometry.map { GeoLocation(it) }3 val simulationStrategy = InterpolationStrategy(routeGeoLocations)4 locationProvider = SimulationLocationProvider.create(strategy = simulationStrategy)5 tomTomNavigation.navigationEngineRegistry.updateEngines(6 locationProvider = locationProvider7 )8 locationProvider.enable()9} - Once navigation is started, the camera is set to follow the user position, and the location indicator is changed to a chevron. To match raw location updates to the routes, use
MapMatchedLocationProvider
and set it to theTomTomMap
.1private fun setMapMatchedLocationProvider() {2 val mapMatchedLocationProvider = MapMatchedLocationProvider(tomTomNavigation)3 tomTomMap.setLocationProvider(mapMatchedLocationProvider)4 mapMatchedLocationProvider.enable()5} - Set the bottom padding on the map. The padding sets a safe area of the
MapView
in which user interaction is not received. It is used to uncover the chevron in the navigation panel.1private fun setMapNavigationPadding() {2 val paddingBottom = resources.getDimensionPixelOffset(R.dimen.map_padding_bottom)3 val padding = Padding(0, 0, 0, paddingBottom)4 tomTomMap.setPadding(padding)5} - Stop the navigation process using
NavigationFragment
. This hides the UI elements and calls theTomTomNavigation.stop()
method. Don’t forget to reset any map settings that were changed, such as camera tracking, location marker, and map padding.1private fun stopNavigation() {2 navigationFragment.stopNavigation()3 tomTomMap.cameraTrackingMode = CameraTrackingMode.None4 tomTomMap.enableLocationMarker(LocationMarkerOptions(LocationMarkerOptions.Type.Pointer))5 resetMapPadding()6 navigationFragment.removeNavigationListener(navigationListener)7 tomTomNavigation.removeProgressUpdatedListener(progressUpdatedListener)8 clearMap()9 initLocationProvider()10 enableUserLocation()11}
Remember to close
TomTomNavigation
if it is no longer needed to release resources.
Run the application. You should see a globe showing the user’s location. Set the destination point with a long press. If you want to start navigation along the drawn route, tap it. Navigation should start with a guidance panel and voice instructions.

Next steps
The TomTom Navigation
SDK allows you to customize the appearance of the map and its overlays, use your own Navigation UI components, or provide a custom implementation of certain navigation behaviors. See the following guides for more information: