Migrate from Mapbox

VERSION 1.20.0
PUBLIC PREVIEW

This tutorial contrasts features of the Mapbox SDK and TomTom SDKs. It uses a simple navigation application created using both the Mapbox and TomTom SDKs to highlight these differences. The application displays the user’s location on a map. It also allows the user to enable and disable a traffic layer on the map. When the user does a long tap on the map, the app draws a marker at the selected location. Next, the app calculates a route from the user’s location to the selected destination and displays it on the map. Finally, the app performs navigation along the route. During navigation, the app provides information about upcoming maneuvers, the estimated time and distance remaining on the trip, and speed limits.

Prerequisites

This tutorial does not discuss the configuration of Mapbox SDK in the project. The following steps describe how to prepare your project to use the TomTom SDKs:

  1. Install Android Studio if you don’t already have it.

  2. Make sure to use Gradle in your project. We are no longer supporting Maven. Contact us if your project is using Maven instead of Gradle.

  3. Create a new project or open an existing one. Make sure that the minimum SDK API level is set to at least 26 (Android 8.0 "Oreo") by making the following changes in the android block of your app’s build.gradle.kts file.

    1android {
    2 defaultConfig {
    3 minSdk = 26
    4 }
    5}
  4. To prevent duplication of the libc++_shared.so file in your Android Gradle build, add the following packaging option to the android block of your app’s build.gradle.kts file.

    1android {
    2 packaging {
    3 jniLibs.pickFirsts.add("lib/**/libc++_shared.so")
    4 }
    5}

    This ensures that only one copy of libc++_shared.so is included in the build output, addressing the issue of multiple copies from different sources.

  5. To prevent potential errors during app start-up, it’s important to ensure that OpenGL ES 3.0 support is enabled in the Android Studio emulator. If your emulator supports it, navigate to Settings, choose "Renderer maximum (up to OpenGL ES 3.1)" for the "OpenGL ES API level (requires restart)" field, and then restart the emulator to apply the changes.

Configuring project dependencies

  1. Add a maven block to your settings.gradle.kts file to specify the URI for repositories.tomtom.com.

    1dependencyResolutionManagement {
    2 repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    3 repositories {
    4 google()
    5 mavenCentral()
    6 maven {
    7 url = uri("https://repositories.tomtom.com/artifactory/maven")
    8 }
    9 }
    10}
  2. Verify that everything works as expected by adding a Maps SDK dependency to the build.gradle.kts file of your application module. For example, com.tomtom.sdk.maps:map-display. Synchronize the project.

    val version = "1.20.0"
    implementation("com.tomtom.sdk.maps:map-display:$version")
  3. Get your TomTom API key from the TomTom Developer Portal. To find out how, refer to the How to get a TomTom API key guide.

  4. Store the TomTom API key to a project property in your project gradle.properties file. Replace api_key_placeholder with the actual TomTom API key.

    tomtomApiKey=api_key_placeholder
  5. Declare the tomtomApiKey variable within the build.gradle.kts file, outside of the android block.

    val tomtomApiKey: String by project
  6. Map the TomTom API key property to a custom field of the gradle BuildConfig class in the android block of your app’s build.gradle.kts file.

    1android {
    2 buildFeatures {
    3 buildConfig = true
    4 }
    5 buildTypes.configureEach {
    6 buildConfigField("String", "TOMTOM_API_KEY", "\"$tomtomApiKey\"")
    7 }
    8}

    To use the TomTom API key in your application code, it is sufficient to access the newly added BuildConfig field.

    val apiKey = BuildConfig.TOMTOM_API_KEY

Now that you’ve completed the project setup, here is what you can do next.

  1. If you don’t have an API Key visit the How to get a TomTom API Key site and create one.
  2. Create fields with the API Keys in your module’s build.gradle.kts, which will be used later in the application:
    1android {
    2 defaultConfig {
    3 resValue("string", "mapbox_access_token", "YOUR_MAPBOX_ACCESS_TOKEN")
    4 buildConfigField("String", "TOMTOM_API_KEY", ""YOUR_TOMTOM_API_KEY"")
    5 }
    6}

Displaying a map

Mapbox

To display a map using the Mapbox Maps SDK for Android, complete the following steps:

  1. Add the maps dependency in your module’s build.gradle.kts.
    implementation("com.mapbox.maps:android:10.3.0")
  2. In the XML layout, provide the MapView map interface.
    1<com.mapbox.maps.MapView
    2 android:id="@+id/mapView"
    3 android:layout_width="match_parent"
    4 android:layout_height="0dp"
    5 app:layout_constraintBottom_toTopOf="@+id/configuration_view"
    6 app:layout_constraintEnd_toEndOf="parent"
    7 app:layout_constraintStart_toStartOf="parent"
    8 app:layout_constraintTop_toTopOf="parent" />
  3. Finally, get the instance of the map in the activity/fragment.
    1mapView = binding.mapView
    2mapboxMap = mapView.getMapboxMap()
    3mapboxMap.loadStyleUri(Style.MAPBOX_STREETS)

TomTom SDKs

To display a map using the TomTom SDKs, perform the following steps:

  1. Add the Map Display module dependency to the module’s build.gradle.kts.
    implementation("com.tomtom.sdk.maps:map-display:1.20.0")
  2. Provide a container within which the map will be displayed to the XML layout.
    1<androidx.fragment.app.FragmentContainerView
    2 android:id="@+id/map_container"
    3 android:layout_width="match_parent"
    4 android:layout_height="0dp"
    5 app:layout_constraintBottom_toTopOf="@+id/configuration_view"
    6 app:layout_constraintEnd_toEndOf="parent"
    7 app:layout_constraintStart_toStartOf="parent"
    8 app:layout_constraintTop_toTopOf="parent" />
  3. In the activity/fragment, configure MapOptions and initialize MapFragment. Place that instance in the container you prepared in the previous step.
    1val mapOptions =
    2 MapOptions(
    3 mapKey = BuildConfig.TOMTOM_API_KEY,
    4 )
    5val mapFragment = MapFragment.newInstance(mapOptions)
    6childFragmentManager.beginTransaction()
    7 .replace(R.id.map_container, mapFragment)
    8 .commit()
  4. Every interaction performed on the map is handled using the TomTomMap object. To get the map instance set an MapReadyCallback to the MapFragment.
    1mapFragment.getMapAsync { map ->
    2 this.tomTomMap = map
    3 showUserLocation()
    4 showTraffic(configurationView.trafficSwitch.isChecked)
    5 handleTrafficSwitch()
    6 handleMapLongClick()
    7}
Globe view

Showing user location

The next step is showing the user location on the map. To do this, Android 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. Check how to grant location permissions in Android by visiting here.

Mapbox

To show the user’s map location in the Mapbox SDK, enable the location plugin.

1val locationPlugin = mapView.location
2locationPlugin.updateSettings {
3 this.enabled = true
4 this.locationPuck = locationPlugin.createDefault2DPuck(requireContext())
5}
6locationPlugin.addOnIndicatorPositionChangedListener(onIndicatorPositionChangedListener)

Observe the indicator position changes to get the latest updated user location.

1private val onIndicatorPositionChangedListener =
2 OnIndicatorPositionChangedListener {
3 lastUserLocation = it
4 }

TomTom SDKs

Use LocationProvider to display the user location in the TomTom SDKs. Provide the initialized engine to the TomTomMap instance and enable it to start updating the location. Then set the location marker that will show the user location on the map. If you want to read more about LocationProvider implementations see the Built-in Location Provider guide.

1locationProvider = DefaultLocationProviderFactory.create(context = requireContext())
2tomTomMap.setLocationProvider(locationProvider)
3locationProvider.enable()
4tomTomMap.enableLocationMarker(LocationMarkerOptions(LocationMarkerOptions.Type.Pointer))

Use the last known location provided by LocationProvider as the user’s current location.

val origin = locationProvider.lastKnownLocation?.position ?: return
Location pointer

Adding a marker

This section describes how to add a marker to the map where the user has performed a long click.

Mapbox

The gestures in the Mapbox SDK are handled by the GesturesPlugin. To detect a long click on the map, set the listener to the plugin.

1mapView.gestures.addOnMapLongClickListener { point: Point ->
2 if (mapboxNavigation.getNavigationSessionState() == NavigationSessionState.Idle) {
3 displayMarker(point)
4 requestRoute(point)
5 }
6 true
7}

To operate on markers, start by creating a point annotation manager on the map instance.

annotationManager = mapView.annotations.createPointAnnotationManager()

Use PointAnnotationOptions to specify the marker configuration. Then use the manager to add it to the map.

1val icon =
2 BitmapFactory.decodeResource(
3 resources,
4 com.tomtom.sdk.map.display.common.R.drawable.ic_sdk_tt_compass,
5 )
6 ?: return // Mapbox does not provide default marker
7annotationManager.deleteAll()
8val pointAnnotationOptions =
9 PointAnnotationOptions()
10 .withPoint(point)
11 .withIconImage(icon)
12 .withIconColor(Color.RED)
13annotationManager.create(pointAnnotationOptions)

TomTom SDKs

In the TomTom SDKs, gestures performed on the map are observed by setting various callbacks. In this tutorial, the MapLongClickListener is used. The usage of other gesture listeners is similar.

1tomTomMap.addMapLongClickListener { coordinate: GeoPoint ->
2 if (!isNavigationRunning) {
3 displayMarker(coordinate)
4 requestRoute(coordinate)
5 }
6 true
7}

To display a marker at the selected coordinates, first define its options using the MarkerOptions class. The configured marker is then added to the TomTomMap instance. You can read more about markers in the Working with markers guide.

1tomTomMap.clear()
2val markerOptions =
3 MarkerOptions(
4 coordinate = coordinate,
5 pinImage = ImageFactory.fromResource(com.tomtom.sdk.map.display.common.R.drawable.ic_sdk_tt_compass),
6 )
7tomTomMap.addMarker(markerOptions)
center

Showing a traffic layer

Both the TomTom and Mapbox SDKs support displaying traffic flow on the map. Flow is indicated by different colors on roads, depending on the degree of delay.

Mapbox

To show traffic on the map in the Mapbox SDK, load the special map style that contains that feature.

1if (!showTraffic) {
2 mapboxMap.loadStyleUri(Style.MAPBOX_STREETS)
3} else {
4 mapboxMap.loadStyleUri(Style.TRAFFIC_DAY)
5}

TomTom SDKs

In the TomTom SDKs, traffic flow is shown as a layer on the map.

TomTom SDKs also support showing traffic incidents.

1if (!showTraffic) {
2 tomTomMap.hideTrafficFlow()
3 tomTomMap.hideTrafficIncidents()
4} else {
5 tomTomMap.showTrafficFlow()
6 tomTomMap.showTrafficIncidents()
7}
Traffic flow

Drawing a route

This section describes how to calculate and draw a route from the user’s location to a destination selected with a long click.

Mapbox

To plan a route between the chosen points, initialize MapboxNavigation.

1val navigationOptions =
2 NavigationOptions.Builder(requireContext())
3 .accessToken(getString(R.string.mapbox_access_token))
4 .locationEngine(replayLocationEngine) // Add simulation location engine
5 .build()
6mapboxNavigation =
7 if (MapboxNavigationProvider.isCreated()) {
8 MapboxNavigationProvider.retrieve()
9 } else {
10 MapboxNavigationProvider.create(navigationOptions)
11 }

Use the RouteOptions class to prepare the routing request. After the configured request is performed, the result is returned via RouterCallback.

1val origin = lastUserLocation ?: return
2val routeOptions =
3 RouteOptions.builder()
4 .applyDefaultNavigationOptions()
5 .coordinates(origin = origin, destination = destination)
6 .build()
7mapboxNavigation.requestRoutes(
8 routeOptions,
9 object : RouterCallback {
10 override fun onCanceled(
11 routeOptions: RouteOptions,
12 routerOrigin: RouterOrigin,
13 ) = Unit
14
15 override fun onFailure(
16 reasons: List<RouterFailure>,
17 routeOptions: RouteOptions,
18 ) {
19 (requireActivity() as MainActivity).showToast(getString(R.string.routing_request_failed))
20 }
21
22 override fun onRoutesReady(
23 routes: List<DirectionsRoute>,
24 routerOrigin: RouterOrigin,
25 ) {
26 mapboxNavigation.setRoutes(routes)
27 drawRoutes(routes)
28 enableNavigation()
29 }
30 },
31)

If the call is successful the returned routes are drawn on the map. Before drawing the routes on the map, initialize MapboxRouteLineApi and MapboxRouteLineView. Define the route style using MapboxRouteLineOptions.

private val routeLineApi: MapboxRouteLineApi by lazy { MapboxRouteLineApi(routeLineOptions) }
private val routeLineView: MapboxRouteLineView by lazy { MapboxRouteLineView(routeLineOptions) }

Once the previous classes are initialized you can render the calculated route on the map.

1private fun drawRoutes(routes: List<DirectionsRoute>) {
2 val routeLines = routes.map { RouteLine(it, null) }
3 routeLineApi.setRoutes(routeLines) { routeDrawData ->
4 mapboxMap.getStyle()?.let { mapStyle ->
5 routeLineView.renderRouteDrawData(mapStyle, routeDrawData)
6 }
7 }
8}

TomTom SDKs

To request a route requires a RoutingApi object, which is an access point to the routing functionalities. To create it use the OnlineRoutePlanner class.

routePlanner = OnlineRoutePlanner.create(requireContext(), BuildConfig.TOMTOM_API_KEY)

The routing request is configured similarly to the Mapbox SDK using the RoutePlanningOptions class. The RoutePlanningOptions object is provided to the routing request. The result of the call is returned via RoutePlanningCallback.

1val origin = locationProvider.lastKnownLocation?.position ?: return
2val routePlanningOptions =
3 RoutePlanningOptions(
4 itinerary = Itinerary(origin = origin, destination = destination),
5 guidanceOptions =
6 GuidanceOptions(
7 phoneticsType = InstructionPhoneticsType.Ipa,
8 extendedSections = ExtendedSections.All,
9 ),
10 )
11routePlanner.planRoute(
12 routePlanningOptions,
13 object : RoutePlanningCallback {
14 override fun onSuccess(result: RoutePlanningResponse) {
15 tomTomMap.removeMarkers()
16 result.routes.firstOrNull()?.let {
17 drawRoute(it)
18 tomTomMap.zoomToRoutes(64)
19 routePlan = RoutePlan(it, routePlanningOptions)
20 }
21 }
22
23 override fun onFailure(failure: RoutingFailure) {
24 (requireActivity() as MainActivity).showToast(getString(R.string.routing_request_failed))
25 }
26
27 override fun onRoutePlanned(route: Route) = Unit
28 },
29)

If the routing call is successful, you can draw the Route on the map. To draw it, configure the RouteOptions object, which specifies the appearance of the route, and add it to the TomTomMap.

1private fun drawRoute(route: Route) {
2 val geometry = route.geometry
3 val routeOptions =
4 RouteOptions(
5 geometry = geometry,
6 departureMarkerVisible = true,
7 destinationMarkerVisible = true,
8 )
9 tomTomMap.addRoute(routeOptions)
10}
Adding a route

Read more about routing in the Planning routes guide.

The last part of this tutorial is about navigation along the previously calculated route. Navigation shows the current speed limit, the next maneuver, and the estimated time and distance remaining for the trip. For the purposes of this tutorial, navigation is simulated in both cases. To use real location data for navigation you must replace LocationProvider with one that provides real data.

Mapbox

Only the main functions of Mapbox SDK navigation are described. The entry point to navigation is the MapboxNavigation class. An instance of it was already created for planning a route. The ReplayLocationProvider was provided during initialization. This engine is responsible for simulating location updates.

Set the route returned by the routing request to navigation. The route defines a list of coordinates along which navigation is performed.

mapboxNavigation.setRoutes(routes)

Once the route is set to navigation, you can start the trip session.

1mapboxNavigation.startTripSession()
2setChevronLocationPuck()
3navigationCamera.requestNavigationCameraToFollowing()
4startLocationSimulationUpdates(route)
5showNavigationComponents()

Navigation UI components must be configured and initialized separately. This tutorial only discusses the maneuver component, which displays the next action and the distance to it.

First, add the maneuver view to the layout.

1<com.mapbox.navigation.ui.maneuver.view.MapboxManeuverView
2 android:id="@+id/maneuver_view"
3 android:layout_width="match_parent"
4 android:layout_height="wrap_content"
5 android:visibility="gone"
6 android:layout_margin="4dp"
7 app:layout_constraintEnd_toEndOf="parent"
8 app:layout_constraintStart_toStartOf="parent"
9 app:layout_constraintTop_toTopOf="parent" />

Then you can access the view in the activity/fragment.

maneuverView = binding.maneuverView

Once the maneuver view is ready, update it with the upcoming maneuvers during the navigation session. To do this, MapboxManeuverApi must be initialized.

1private val distanceFormatter: DistanceFormatterOptions by lazy {
2 DistanceFormatterOptions.Builder(requireContext())
3 .unitType(UnitType.METRIC)
4 .build()
5}
6
7private val maneuverApi: MapboxManeuverApi by lazy {
8 MapboxManeuverApi(MapboxDistanceFormatter(distanceFormatter))
9}

Maneuvers are updated depending on the progress along the route. This means that the progress must be observed and the related data supplied to the maneuver API. Then the view is updated.

1private val routeProgressObserver =
2 RouteProgressObserver { routeProgress ->
3 viewportDataSource.onRouteProgressChanged(routeProgress)
4 viewportDataSource.evaluate()
5 displayManeuver(routeProgress)
6 displayTripProgress(routeProgress)
7 }
8private fun displayManeuver(routeProgress: RouteProgress) {
9 val maneuvers = maneuverApi.getManeuvers(routeProgress)
10 maneuverView.renderManeuvers(maneuvers)
11}

Each of the navigation UI components is handled in a similar way. Some of them need different listeners, to observe different navigation data.

TomTom SDKs

This tutorial contains a superficial description of navigation. If you want to learn more about how to use the Navigation SDK, you can read the guides. A good place to start is Navigation quickstart guide.

The entry point to interact with navigation is the TomTomNavigation class. Therefore it must be initialized before starting a trip session. This application uses SimulationLocationProvider to simulate navigation. It can be replaced with any other LocationProvider. Read about different types of `LocationProvider`s and how they work in the TomTom SDKs in the Built-in Location Provider guide.

1navigationTileStore =
2 NavigationTileStore.create(
3 context = requireContext(),
4 navigationTileStoreConfig =
5 NavigationTileStoreConfiguration(
6 apiKey = BuildConfig.TOMTOM_API_KEY,
7 ),
8 )
9val routeGeometry =
10 routePlan?.route?.geometry?.map { GeoLocation(position = it) } ?: return
11val simulationStrategy =
12 InterpolationStrategy(routeGeometry, currentSpeed = Speed.metersPerSecond(20.0))
13locationProvider = SimulationLocationProvider.create(simulationStrategy)
14tomTomNavigation =
15 OnlineTomTomNavigationFactory.create(
16 OnlineConfiguration(
17 context = requireContext(),
18 navigationTileStore = navigationTileStore,
19 locationProvider = locationProvider,
20 routePlanner = routePlanner,
21 ),
22 )
center

Summary

This tutorial instructed you on how to move a basic app from Mapbox’s SDKs to TomTom’s SDKs. Now you can enrich your app with TomTom’s features and functions.

If you want to learn more, take a look at our other tutorials: