This example performs real turn-by-turn navigation along a route rendered on an interactive map, from the device's current position to a fixed destination (Paris). While navigating, the screen shows three panels driven by live navigation updates:
a top panel with the next-turn icon, the distance to the turn and the next street name (or a signpost / road-code shield when available);
a traffic panel that appears when a traffic event lies ahead, showing its description, the distance to it and the delay it adds;
a bottom panel with the estimated time of arrival, the remaining travel time and the remaining distance.
The camera follows the current position, and a floating button re-enters follow mode after the user pans the map away.
MainActivity retains a single NavigationService and a NavigationListener. The listener receives the stream of navigation events: when navigation starts, when the next instruction changes, when the status changes (waiting for a route, waiting for GPS, running…), when the destination is reached, on errors, and when a voice instruction should be played. The navRoute helper fetches the route currently being navigated, which the UI uses to read estimated time of arrival, remaining time and distance.
A separate ProgressListener tracks the route-calculation progress and toggles the progress bar. It only shows the bar the first time, so the indicator does not flash on every route recalculation during the trip.
Navigation can only start once several conditions are met: the worldwide road map must be downloaded and up to date, location services must be enabled, the runtime location permissions must be granted, and a first valid GPS position must be available. These steps are chained together.
When the road map reaches EOffboardListenerStatus.UpToDate, the listener clears itself and checks the location status; if location is enabled it requests the permissions.
SdkSettings.onWorldwideRoadMapSupportStatus ={ status ->
if(status == EOffboardListenerStatus.UpToDate){
SdkSettings.onWorldwideRoadMapSupportStatus ={}
if(checkLocationStatus()){
requestPermissions()
}
}
}
Once the permissions are granted, the app waits for the first valid improved position before starting. If a valid position is already available it starts immediately; otherwise it subscribes a PositionListener and starts as soon as the first valid position arrives, then removes itself.
startNavigation defines the destination, cancels any navigation already in progress, and calls navigationService.startNavigation with the navigation and routing-progress listeners. The call returns synchronously whether navigation could be started; on failure the error is reported in a dialog.
When navigation starts (the onNavigationStarted callback above), the route is drawn on the map with presentRoute, the camera enters follow mode with followPosition, and the navigation panels are made visible. Entering follow mode hides the follow GPS button - it is only needed when the camera is not following the current position.
The follow GPS button is wired up earlier, when the default map view is created. onDefaultMapViewCreated waits for a first valid position and then calls enableGPSButton on the main thread.
enableGPSButton sets up the follow-mode transitions: when the user pans away from the current position the button reappears and the panels are hidden; tapping the button calls followPosition to re-center and resume following.
Each time the SDK reports a new instruction through onNavigationInstructionUpdated, updateNavigationInstruction refreshes the top panel. The displayable values are gathered on the SDK thread by collectNavigationUiData: the next street name (or turn instruction), the next-turn icon, the distance to the turn, and the estimated time of arrival / remaining travel time (RTT) / remaining travel distance (RTD) read from the navigated route. It also resolves a signpost image, falling back to a road-code shield when there is no signpost. The remaining travel time is colored orange or red according to the traffic severity; if it stays black there is no traffic delay on the route.
The next-turn icon is rendered from the instruction's abstract geometry image with GemUtilImages.asBitmap, using a white-fill/black-outline style. To avoid redrawing the same icon on every update, the image UID is cached and the bitmap is skipped when it has not changed.
After updating the instruction, updateNavigationInstruction also refreshes the traffic panel via updateTrafficPanel. It looks for the nearest traffic event ahead on the route that adds a delay; if none is found (or the top panel is hidden) the panel is hidden. getTrafficEvent walks the route's traffic events and computes, from the remaining travel distance, whether each event is still ahead or whether the driver is already inside it - which determines whether the panel shows the distance to the event or the distance remaining inside it.
When the destination is reached (onDestinationReached) or an error occurs (onNavigationError), onNavigationEnded hides the navigation panels and the route, showing a dialog only for genuine errors (not for a normal cancellation).