Turn-by-turn navigation
Navigation SDK for Android is only available upon request. Contact us to get started.
Turn-by-turn navigation is navigation along a calculated route. It provides information about the next maneuvers and the progress along the current route. To begin, add the navigation module to your project and set up a TomTomNavigation
object. You can learn how to do this in the Quickstart guide.
Starting navigation
Once the TomTomNavigation
object is initialized, you can start navigation. Turn-by-turn navigation requires NavigationOptions
for navigation to follow. NavigationOptions
encapsulate an active RoutePlan
.
A RoutePlan
consists of a Route
and the RoutePlanningOptions
objects used for planning it. You can learn more about how to plan a Route
in the Planning a route guide.
val routePlan = RoutePlan(route = route, routePlanningOptions = routePlanningOptions)
Now you can use the prepared RoutePlan
to create NavigationOptions
and start navigation. To do this, call the start(NavigationOptions)
method on your TomTomNavigation
object.
tomTomNavigation.start(NavigationOptions(routePlan))

TomTomNavigation
also supports manually stopping navigation. The TomTomNavigation.stop()
method stops the current navigation session and clears all data related to it.
tomTomNavigation.stop()
If navigation was not started, the stop method will have no effect.
Updating the route
Once TomTomNavigation
is started, the RoutePlan
you’re following can be changed at any time; either manually or automatically by the navigation session.
The route changes during navigation are observed using:
- The
RouteUpdatedListener
- provides information about the route updates that do not change the route geometry, seeRouteUpdatedReason
. - The
RouteAddedListener
- provides information about the new route being added to the navigation session. - The
RouteRemovedListener
- provides information about the route being removed from the navigation session. - The
ActiveRouteChangedListener
- provides information about the new route being applied as an active route; the route must have been previously added to the session.
You can manually change the RoutePlan
you’re following at any time.
tomTomNavigation.setActiveRoutePlan(routePlan)
A manual
RoutePlan
update results in aRouteAddedReason.ManuallyUpdated
reason provided in theRouteAddedListener
.Other reasons can occur after route replanning.
1val routeAddedListener =2 RouteAddedListener { route: Route, options: RoutePlanningOptions, reason: RouteAddedReason ->3 // YOUR CODE GOES HERE4 }5val routeRemovedListener =6 RouteRemovedListener { route: Route, reason: RouteRemovedReason ->7 // YOUR CODE GOES HERE8 }9val activeRouteChangedListener =10 ActiveRouteChangedListener { route: Route ->11 // YOUR CODE GOES HERE12 }13val routeUpdatedListener =14 RouteUpdatedListener { route: Route, reason: RouteUpdatedReason ->15 // YOUR CODE GOES HERE16 }17tomTomNavigation.addRouteAddedListener(routeAddedListener)18tomTomNavigation.addRouteRemovedListener(routeRemovedListener)19tomTomNavigation.addActiveRouteChangedListener(activeRouteChangedListener)20tomTomNavigation.addRouteUpdatedListener(routeUpdatedListener)
To remove previously-added listeners, call the appropriate methods on the TomTomNavigation
.
1tomTomNavigation.removeRouteAddedListener(routeAddedListener)2tomTomNavigation.removeRouteRemovedListener(routeRemovedListener)3tomTomNavigation.removeActiveRouteChangedListener(activeRouteChangedListener)4tomTomNavigation.removeRouteUpdatedListener(routeUpdatedListener)
Modifying the RoutePlanningOptions of the active route
The TomTom Navigation SDK offers extensions that let the user modify the active route’s RoutePlanningOptions
. These extensions are added to support the following use cases:
- The user wants to be able to skip an unvisited
RouteStop
. Note that the final destination cannot be skipped. - The user wants to skip a charging station by doing a soft avoid. This means the
RoutePlanner
tries calculating a route that avoids the specified charging station. However, the planner might be unable to find a reachable route without visiting that charging station.
Skip route stop
The user must get the latest RoutePlanningOptions
, plan the route, and begin navigating using the setActiveRoutePlan method
. The following snippet shows how to do it:
1val navigationSnapshot = tomTomNavigation.navigationSnapshot23val routeStopThatShouldBeSkipped =4 requireNotNull(navigationSnapshot!!.routes.first().waypoints.first()) {5 "Navigation should not be stopped and there should be a waypoint that the user wants to skip."6 }78// Create modified route planning options for the active route.9val modifiedRoutePlanningOptions =10 navigationSnapshot.currentActiveRoutePlanningOptions11 .skipRouteStop(routeStopThatShouldBeSkipped)1213// Plan a modified route and change the active route plan if successfully planned.14routePlanner.planRoute(modifiedRoutePlanningOptions).ifSuccess {15 // Choose a route, the first one is the best and usually fits the needs of the user.16 val chosenRoute = it.routes.first()1718 tomTomNavigation.setActiveRoutePlan(19 RoutePlan(20 route = chosenRoute,21 routePlanningOptions = modifiedRoutePlanningOptions,22 ),23 )24}.ifFailure {25 // Handle failure26}
Saving and resuming navigation
If the
NavigationVisualization
object is used, make sure theNavigationResumeSnapshotRenewer
object is initialized after it.
Whether the app crashed, it was accidentally terminated, or the system needed to free up resources, saving an ongoing navigation session ensures that TomTomNavigation
can return to its previous state the next time the app is launched.
To support navigation session restoration TomTomNavigation
offers the TomTomNavigation.navigationResumeSnapshot
property and the TomTomNavigation.resume(navigationResumeSnapshot: NavigationResumeSnapshot)
method. To serialize NavigationResumeSnapshot
, use the NavigationResumeSnapshot.serializeToFile(snapshotFle: File)
or NavigationResumeSnapshot.serializeToBytes()
methods. For deserialization, use the NavigationResumeSnapshot.deserializeFromFile(file: File)
or NavigationResumeSnapshot.deserializeFromBytes(data: byteArray)
methods.
Saving and resuming a navigation session can be done either automatically or manually.
Saving and resuming a navigation session automatically
In order to start saving the process automatically, create a default implementation of NavigationResumeSnapshotRenewer
. Once navigation is started, a snapshot is saved periodically (30 seconds by default).
1val navigationResumeSnapshotRenewer =2 NavigationResumeSnapshotRenewerFactory.create(3 context = context,4 options = NavigationResumeSnapshotRenewerOptions(),5 tomTomNavigation = tomTomNavigation,6 )
The interval for automatic saving can be set in NavigationResumeSnapshotRenewerOptions
.
1val options = NavigationResumeSnapshotRenewerOptions(saveInterval = 40.seconds)2val navigationResumeSnapshotRenewer =3 NavigationResumeSnapshotRenewerFactory.create(4 context = context,5 options = options,6 tomTomNavigation = tomTomNavigation,7 )
To automatically resume a previously saved navigation session, use the NavigationResumeSnapshotRenewer.resumeNavigation()
method:
1navigationResumeSnapshotRenewer.resumeNavigation(2 callback =3 object :4 Callback<NavigationResumeSnapshot, NavigationResumeSnapshotRenewerFailure> {5 override fun onSuccess(result: NavigationResumeSnapshot) {6 // YOUR CODE GOES HERE7 }89 override fun onFailure(failure: NavigationResumeSnapshotRenewerFailure) {10 // YOUR CODE GOES HERE11 }12 },13)
To resume a previously saved navigation session manually, use the NavigationResumeSnapshotRenewer.latestNavigationResumeSnapshot()
method:
1navigationResumeSnapshotRenewer.latestNavigationResumeSnapshot(2 callback =3 object :4 Callback<NavigationResumeSnapshot, NavigationResumeSnapshotRenewerFailure> {5 override fun onSuccess(result: NavigationResumeSnapshot) {6 tomTomNavigation.resume(result)7 // YOUR CODE GOES HERE8 }910 override fun onFailure(failure: NavigationResumeSnapshotRenewerFailure) {11 // YOUR CODE GOES HERE12 }13 },14)
Saving and resuming a navigation session manually
If you want to save the NavigationResumeSnapshot
as a file, you can use the following snippet:
1val fileName = "navigation_snapshot"2tomTomNavigation.navigationResumeSnapshot()3 .ifSuccess { snapshot ->4 snapshot.serializeToBytes() // or snapshot.serializeToFile(file)5 .ifSuccess { data ->6 val file = File(context.filesDir, fileName)7 FileOutputStream(file).use { fileOutputStream ->8 fileOutputStream.write(data)9 }10 }11 .ifFailure { failure: NavigationResumeSnapshotSerializationFailure ->12 // YOUR CODE GOES HERE13 }14 }15 .ifFailure { failure: NavigationResumeSnapshotFailure ->16 // YOUR CODE GOES HERE17 }
To resume a previously saved navigation session, you can use the following snippet:
1val fileName = "navigation_snapshot"2val file = File(context.filesDir, fileName)3if (file.exists()) {4 NavigationResumeSnapshot.deserializeFromFile(file)5 .ifSuccess { snapshot ->6 tomTomNavigation.resume(navigationResumeSnapshot = snapshot)7 }8 .ifFailure { failure: NavigationResumeSnapshotSerializationFailure ->9 // YOUR CODE GOES HERE10 }11}
After resuming, the
RouteAddedListener
is invoked with theRouteAddedReason
argument set toRouteAddedReason.NavigationResumed
. TheTomTomNavigation.language
andTomTomNavigation.unitSystem
are applied from the previous session.You can apply a new language and unitSystem via the
TomTomNavigation
object after resuming the session.
To improve performance, save the NavigationResumeSnapshot
after key events that bring significant changes in the navigation state, like:
- Starting navigation along a route.
- Refreshing the route.
- Deviating from the route.
- Visiting a waypoint.
Route progress
The position-dependent data fields are collectively known as the "Route Progress" data. Examples of these data are position on route (offset from the beginning) and remaining travel time. These fields are updated on every position update roughly once per second for every followed route in the system. You can listen for changes to route progress. To listen for changes, set ProgressUpdatedListener
to the TomTomNavigation
object. ProgressUpdatedListener
is triggered whenever the user’s progress along the Route
is changed. It provides the current RouteProgress
, which contains, among other things, the arrival time and the remaining distance along the route.
1val progressUpdatedListener =2 ProgressUpdatedListener { progress: RouteProgress ->3 // YOUR CODE GOES HERE4 }5tomTomNavigation.addProgressUpdatedListener(progressUpdatedListener)
To remove a previously-added listener, call TomTomNavigation.removeProgressUpdatedListener(ProgressUpdatedListener)
.
tomTomNavigation.removeProgressUpdatedListener(progressUpdatedListener)
Route deviations
During the navigation, the TomTomNavigation
tracks your position relative to the navigated routes and provides information which ones are followed. To listen for such updates, use the RouteTrackingStateUpdatedListener
.
The RouteTrackingState
object is an argument provided by the RouteTrackingStateUpdatedListener
. It contains a list of the followed and unfollowed routes. Additionally, it tells when the driver deviates from all the routes. To verify if the driver deviated from the route, check if the RouteTrackingState.hasDeviated
property is true.
To listen to the route tracking updates, set RouteTrackingStateUpdatedListener
to the TomTomNavigation
object.
1val routeTrackingStateUpdatedListener =2 RouteTrackingStateUpdatedListener { routeTrackingState: RouteTrackingState ->3 // YOUR CODE GOES HERE4 }5tomTomNavigation.addRouteTrackingStateUpdatedListener(routeTrackingStateUpdatedListener)
To remove RouteTrackingStateUpdatedListener
use the TomTomNavigation.removeRouteTrackingStateUpdatedListener(RouteTrackingStateUpdatedListener)
method.
tomTomNavigation.removeRouteTrackingStateUpdatedListener(routeTrackingStateUpdatedListener)
If the driver does deviate from the route, navigation enters free driving mode. This means that navigation runs without a RoutePlan
. The RoutePlan
automatically replans using the same cost model as used in the original RoutePlan
. You can find more details about automatic replanning in the Replanning on deviation section.
You can disable automatic replanning and provide a new
RoutePlan
manually using thesetActiveRoutePlan method
.
Route guidance
The combination of maneuver instructions and maneuver announcements is called Route Guidance.
During navigation, TomTomNavigation
generates a guidance update after each location change. Generated guidance consists of the next instructions, the distance to a maneuver, and an announcement if the distance is within a suitable range. The generated guidance is then sent to GuidanceUpdatedListener
. Note that GuidanceUpdatedListener
should be set before TomTomNavigation
is started.
GuidanceUpdatedListener
has three methods:
onInstructionsChanged(List<GuidanceInstruction>)
- This reports a change to guidance instructions.GuidanceInstruction
contains information describing a maneuver, e.g., 'Turn right', 'Keep left', 'Take the Motorway'.onAnnouncementGenerated(GuidanceAnnouncement, Boolean)
- This is triggered when an announcement is generated.
The GuidanceAnnouncement
is an announcement point with its own message, location, and distance to the instruction point. The shouldPlay
flag indicates whether announcement should be triggered according to guidelines.
onDistanceToNextInstructionChanged(Distance, List<GuidanceInstruction>, InstructionPhase)
- This is called with each change of distance to the instruction. The first parameter is the distance in meters to the instruction. The second parameter provides the next instructions. The third parameter is the current triggering phase of the instruction.
1val guidanceUpdatedListener =2 object : GuidanceUpdatedListener {3 override fun onInstructionsChanged(instructions: List<GuidanceInstruction>) {4 // YOUR CODE GOES HERE5 }67 override fun onAnnouncementGenerated(8 announcement: GuidanceAnnouncement,9 shouldPlay: Boolean,10 ) {11 // YOUR CODE GOES HERE12 }1314 override fun onDistanceToNextInstructionChanged(15 distance: Distance,16 instructions: List<GuidanceInstruction>,17 currentPhase: InstructionPhase,18 ) {19 // YOUR CODE GOES HERE20 }21 }22tomTomNavigation.addGuidanceUpdatedListener(guidanceUpdatedListener)
To remove a previously-added GuidanceUpdatedListener
use the TomTomNavigation.removeGuidanceUpdatedListener(GuidanceUpdatedListener)
method.
tomTomNavigation.removeGuidanceUpdatedListener(guidanceUpdatedListener)
Instruction language can be changed by updating TomTomNavigation.preferredLanguage
property.
tomTomNavigation.preferredLanguage = Locale.FRANCE
Current language can be retrieved by TomTomNavigation.language
property.
Lane level guidance
TomTomNavigation
has built-in support for generating lane guidance. Lane guidance is generated for each LaneSection
object in a Route
.
You can learn more about how to request a route with a LaneSection
by reading the Route sections guide.
The LaneGuidance
object includes:
- lanes - This is an object that consists of a list with directions and an optional lane direction that the driver should follow.
- laneSeparators - This is a list of lane separators.
- routeOffset - This is the distance in meters from the start of the route to the start of the lanes.
- length - This is the length in meters of the lane section.
The generated LaneGuidance
is sent to LaneGuidanceUpdatedListener
. LaneGuidanceUpdatedListener
has two methods:
onLaneGuidanceStarted(LaneGuidance)
- This is triggered when lane guidance appears.onLaneGuidanceEnded(LaneGuidance)
- This is triggered when lane guidance disappears.
1val laneGuidanceUpdatedListener =2 object : LaneGuidanceUpdatedListener {3 override fun onLaneGuidanceStarted(laneGuidance: LaneGuidance) {4 // YOUR CODE GOES HERE5 }67 override fun onLaneGuidanceEnded(laneGuidance: LaneGuidance) {8 // YOUR CODE GOES HERE9 }10 }11tomTomNavigation.addLaneGuidanceUpdatedListener(laneGuidanceUpdatedListener)
To remove a previously-added LaneGuidanceUpdatedListener
, use the TomTomNavigation.removeLaneGuidanceUpdatedListener(LaneGuidanceUpdateListener)
method.
tomTomNavigation.removeLaneGuidanceUpdatedListener(laneGuidanceUpdatedListener)
Arrival experience
The Navigation module uses the generated RouteProgress
to detect that the user has arrived at the destination. Once arrival is detected it triggers DestinationArrivalListener
. This means that the ArrivalDetectionEngine
has detected an arrival.
At that point navigation continues to be in turn-by-turn mode until it’s stopped.
1val destinationArrivalListener =2 DestinationArrivalListener {3 // YOUR CODE GOES HERE4 }5tomTomNavigation.addDestinationArrivalListener(destinationArrivalListener)
DestinationArrivalListener
can be removed as below.
tomTomNavigation.removeDestinationArrivalListener(destinationArrivalListener)
Waypoint arrival
The Route
being followed can contain route stops that the driver wants to visit before arriving at the destination. These stops, called waypoints, are included in routeStops
as instances of the type RouteStop
. You can find more details on waypoints in the Waypoints and custom routes guide.
Arriving at a waypoint can be divided into three phases: Approaching, Visiting, and Departing. Once waypoint arrival state change is detected it triggers WaypointArrivalListener
. This means that the ArrivalDetectionEngine
has successfully detected an arrival at the waypoint. It determines arrival by verifying whether the distance along the route is within the arrival radius of the waypoint. This distance threshold is set to 100 meters for motorways and 50 meters for other roads. The waypoint is also automatically marked as departed when the user is on an active route and has increased the distance along the route by the distance threshold. If the user deviates from the active route near a waypoint, the waypoint will be considered departed if the user moves away from the waypoint by more than the distance threshold in a straight line.
1val waypointArrivalListener =2 object : WaypointArrivalListener {3 override fun onWaypointArrived(4 waypoint: RouteStop,5 route: Route,6 ) {7 // YOUR CODE GOES HERE8 }910 override fun onWaypointDeparted(11 waypoint: RouteStop,12 route: Route,13 ) {14 // YOUR CODE GOES HERE15 }16 }17tomTomNavigation.addWaypointArrivalListener(waypointArrivalListener)
WaypointArrivalListener
can be removed as shown in the following figure.
tomTomNavigation.removeWaypointArrivalListener(waypointArrivalListener)
The Navigation module allows you to manually mark a waypoint as visited, independent of ArrivalDetectionEngine
.
tomTomNavigation.departFromWaypoint(waypoint)
This method throws an exception if the specified waypoint has not been previously arrived at or has no effect if it has already been departed from.
As a result of successful action, the WaypointArrivalListener.onWaypointDeparted
is notified. This notification signifies the completion of arrival detection for the specific waypoint. Navigation then switches its focus to detecting arrival for the next waypoint, if one exists.
Next steps
Since you have learned how to work with turn-by-turn navigation, here are recommendations for the next steps: