Migrate to the latest version

VERSION 0.3.34
PUBLIC PREVIEW

This tutorial contrasts how to implement core functionality in the current and in the previous version of Maps SDK. The tutorial topics are:

Project set up

  1. You need a TomTom API key to use TomTom SDKs. If you don’t have one go to How do I get a TomTom API Key?.
  2. Install Android Studio if you don’t already have it.
  3. 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 compile SDK API level is set to 31.
  4. Add the packagingOptions.
    1android {
    2 ...
    3 packagingOptions {
    4 pickFirst "lib/**/libc++_shared.so"
    5 }
    6}
  5. To get access to the TomTom SDK repository, add the following to your settings.gradle file
    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}
  6. Add the dependencies that your project requires. This tutorial uses the Maps Display, Location Android, Search Client and Online Routing Client modules.
    1implementation "com.tomtom.sdk:maps-display:0.3.34"
    2implementation "com.tomtom.sdk:location-android:0.3.34"
    3implementation "com.tomtom.sdk:search-client-online:0.3.34"
    4implementation "com.tomtom.sdk:routing-client-online:0.3.34"
  7. Create build config fields with the API keys. These will be used later in the application.
    1android {
    2 ...
    3 defaultConfig {
    4 ...
    5 buildConfigField("String", "MAPS_API_KEY", ""YOUR_API_KEY"")
    6 buildConfigField("String", "SEARCH_API_KEY", ""YOUR_API_KEY"")
    7 buildConfigField("String", "ROUTING_API_KEY", ""YOUR_API_KEY"")
    8 }
    9}

Displaying a map

Legacy SDK

To display a map in the TomTom Maps SDK, you had to perform following steps:

  1. Add a container for the map to the view.

    1<androidx.fragment.app.FragmentContainerView
    2 android:id="@+id/map_container"
    3 android:layout_width="match_parent"
    4 android:layout_height="match_parent" />
  2. Initialize the MapFragment in an Activity or a Fragment class, using MapProperties to provide a valid TomTom API key and other optional properties.

    1val apiKeys = mapOf(ApiKeyType.MAPS_API_KEY to BuildConfig.MAPS_API_KEY)
    2val mapProperties = MapProperties.Builder()
    3 .keys(apiKeys)
    4 .padding(MapPadding(32.0, 0.0, 0.0, 0.0))
    5 .build()
    6val mapFragment = MapFragment.newInstance(mapProperties)
  3. Use a FragmentManager to replace the map container with the created MapFragment.

    1childFragmentManager.beginTransaction()
    2 .replace(R.id.map_container, mapFragment)
    3 .commit()
  4. At this point the map will be displayed. However, to interact with its instance you have to get the TomtomMap object when the map is ready to use. Add the TomTomMap field to the class.

    private lateinit var tomtomMap: TomtomMap
  5. Implement the OnMapReadyCallback interface and provide it to the MapFragment. The 'OnMapReadyCallback.onMapReady(TomtomMap)' method will be called when the map is fully initialized.

    mapFragment.getAsyncMap(this)
    1override fun onMapReady(tomtomMap: TomtomMap) {
    2 this.tomtomMap = tomtomMap
    3 showUserLocation()
    4 enableSearchField()
    5}

TomTom SDKs

Map initialization in the TomTom SDKs is very similar.

  1. Create a container for the map in your view.
    1<androidx.fragment.app.FragmentContainerView
    2 android:id="@+id/map_container"
    3 android:layout_width="match_parent"
    4 android:layout_height="match_parent" />
  2. Prepare a property to hold the TomTomMap instance.
    private lateinit var tomTomMap: TomTomMap
  3. Create MapFragment using the MapOptions class to specify the needed properties.
    1val mapOptions = MapOptions(
    2 mapKey = BuildConfig.MAPS_API_KEY,
    3 padding = Padding(top = 32, bottom = 0, left = 0, right = 0)
    4)
    5val mapFragment = MapFragment.newInstance(mapOptions)
  4. Finally, put the MapFragment in the container using the FragmentManager and set the OnMapReadyCallback to access the map instance when it is ready to be used.
    1childFragmentManager.beginTransaction()
    2 .replace(R.id.map_container, mapFragment)
    3 .commit()
    4mapFragment.getMapAsync(this)
  5. Once the map is ready, assign it to the previously created property.
    1override fun onMapReady(map: TomTomMap) {
    2 this.tomTomMap = map
    3 showUserLocation()
    4 enableSearchField()
    5}

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 ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permissions. On devices that run Android 6.0 or higher, you must request permissions at runtime.

Legacy SDK

In the TomTom Legacy SDK, location permissions are handled internally by the SDK. So to show the user location on the map, you only need to enable the user location layer.

tomtomMap.isMyLocationEnabled = true

TomTom SDKs

By contrast, the TomTom Maps and Navigation SDKs do not support handling permissions. Complete instructions on how to request location permissions can be found here.

  1. If permissions have been granted by the user, you can initialize the location engine.

    private lateinit var locationEngine: LocationEngine
    locationEngine = AndroidLocationEngine(requireContext())
  2. Set the engine to the TomTomMap object. Enable the marker that represents the user location so it can be displayed.

    tomTomMap.setLocationEngine(locationEngine)
    tomTomMap.enableLocationMarker(LocationMarkerOptions(LocationMarkerType.POINTER))
  3. Enable the LocationEngine to receive location updates.

    locationEngine.enable()

Location pointer

This part of the tutorial describes a simple fuzzy search implementation. For more detailed information about searches see the Search module documentation. A good place to start is Search quickstart guide.

With both SDKs, you need to use use an AppCompatAutoCompleteTextView to get the search term from the user. It also displays the results of the search request. Implementing AppCompatAutoCompleteTextView is out of the scope of this tutorial, which only covers functionality within the SDK.

Legacy SDK

  1. The entry point to the Search services is through the SearchApi interface. Create the interface using the OnlineSearchApi class. It requires a context and a valid TomTom API key.

    private lateinit var searchApi: SearchApi
    searchApi = OnlineSearchApi.create(requireContext(), BuildConfig.SEARCH_API_KEY)
  2. The fuzzy search request is built using descriptors, which are then included in the FuzzySearchSpecification along with the query.

    1val searchEngineDescriptor = FuzzySearchEngineDescriptor.Builder()
    2 .typeAhead(true)
    3 .minFuzzyLevel(2)
    4 .maxFuzzyLevel(4)
    5 .build()
    6
    7val fuzzySearchSpecification = FuzzySearchSpecification.Builder(query)
    8 .searchEngineDescriptor(searchEngineDescriptor)
    9 .build()
  3. Use the prepared specification to perform the request. The results are returned using a FuzzyOutcomeCallback that was provided to the request method.

    1searchApi.search(
    2 fuzzySearchSpecification,
    3 object : FuzzyOutcomeCallback {
    4 override fun onError(error: SearchException) {
    5 Toast.makeText(requireContext(), error.localizedMessage, Toast.LENGTH_SHORT).show()
    6 }
    7
    8 override fun onSuccess(fuzzyOutcome: FuzzyOutcome) {
    9 addSearchResultsToSuggestionsAdapter(fuzzyOutcome.fuzzyDetailsList)
    10 }
    11 }
    12)

TomTom SDKs

  1. As in the legacy SDK, the Search services are accessed using the SearchApi class. It also requires a context and the TomTom API key.

    private lateinit var searchApi: SearchApi
    searchApi = OnlineSearchApi.create(requireContext(), BuildConfig.SEARCH_API_KEY)
  2. Use the FuzzySearchOptions class to build the fuzzy search request. You can specify all the parameters using this single class.

    1val fuzzySearchOptions = FuzzySearchOptions.Builder(query)
    2 .minFuzzyLevel(2)
    3 .typeAhead(true)
    4 .build()
  3. Use the newly created FuzzySearchOptions to perform a search request. All the results are returned using the FuzzySearchCallback object.

    1searchApi.fuzzySearch(
    2 fuzzySearchOptions,
    3 object : FuzzySearchCallback {
    4 override fun onError(error: FuzzySearchError) {
    5 Toast.makeText(requireContext(), error.message, Toast.LENGTH_SHORT).show()
    6 }
    7
    8 override fun onSuccess(result: FuzzySearchResponse) {
    9 addSearchResultsToSuggestionsAdapter(result.results)
    10 }
    11 }
    12)

Adding a marker

This section explains how to add a marker at a selected location using each of the SDKs.

Legacy SDK

To add a marker to the map, first create a MarkerBuilder to specify its properties. Then add the MarkerBuilder to the TomTomMap.

1private fun displayMarkerAt(latLng: LatLng) {
2 val markerBuilder = MarkerBuilder(latLng)
3 tomtomMap.addMarker(markerBuilder)
4}

TomTom SDKs

Adding a marker works in the same way as with the TomTom SDKs. The only difference is that the MarkerOptions class is used instead of MarkerBuilder.

1private fun displayMarkerAt(coordinate: GeoCoordinate) {
2 val markerOptions =
3 MarkerOptions(
4 coordinate,
5 ImageFactory.fromResource(R.drawable.center_balloon_bg)
6 ) // No default marker
7 tomTomMap.addMarker(markerOptions)
8}

center

Drawing a route

The last part of this tutorial explains how to plan a route between two locations and draw it on the map.

Legacy SDK

  1. To perform any routing request in the TomTom SDKs, start by initializing a RoutingApi. This is the access point to the routing service.

    private lateinit var routingApi: RoutingApi
    routingApi = OnlineRoutingApi.create(requireContext(), BuildConfig.ROUTING_API_KEY)
  2. Build and perform the request. Specify the route parameters by applying route descriptors to the RouteSpecification class. Then provide the configured specification to the routing call. Possible routes are returned inside the RouteCallback provided to the request method.

    1private fun planRoute(departureLatLng: LatLng, destinationLatLng: LatLng) {
    2 val routeDescriptor = RouteDescriptor.Builder()
    3 .routeType(RouteType.FASTEST)
    4 .considerTraffic(true)
    5 .build()
    6
    7 val routeCalculationDescriptor = RouteCalculationDescriptor.Builder()
    8 .routeDescription(routeDescriptor)
    9 .build()
    10
    11 val routeSpecification = RouteSpecification.Builder(departureLatLng, destinationLatLng)
    12 .routeCalculationDescriptor(routeCalculationDescriptor)
    13 .build()
    14
    15 routingApi.planRoute(
    16 routeSpecification,
    17 object : RouteCallback {
    18 override fun onError(error: RoutingException) {
    19 Toast.makeText(requireContext(), error.localizedMessage, Toast.LENGTH_SHORT).show()
    20 }
    21
    22 override fun onSuccess(routePlan: RoutePlan) {
    23 val route = routePlan.routes.firstOrNull() ?: return
    24 drawRoute(route)
    25 }
    26 }
    27 )
    28}
  3. Draw the calculated route on the map. You can define the appearance of the route using the RouteStyleBuilder class. The RouteBuilder is a representation of the path to add to the map. You must provide it with a list of coordinates. You can also specify the design, but this is optional. All the routes will then be shown in the route overview.

    1val coordinates = route.getCoordinates()
    2val routeStyle = RouteStyleBuilder.create().withFillColor(Color.RED).build()
    3val routeBuilder = RouteBuilder(coordinates)
    4 .style(routeStyle)
    5 .startIcon(
    6 Icon.Factory.fromResources(
    7 requireContext(),
    8 R.drawable.ic_map_route_departure
    9 )
    10 )
    11 .endIcon(
    12 Icon.Factory.fromResources(
    13 requireContext(),
    14 R.drawable.ic_map_route_destination
    15 )
    16 )
    17tomtomMap.addRoute(routeBuilder)
    18tomtomMap.displayRoutesOverview()

TomTom SDKs

  1. As with the TomTom SDKs, the entry point to the routing services for TomTom SDK is through the RoutingApi interface. It must be initialized before any routing calls.

    private lateinit var routingApi: RoutingApi
    routingApi = OnlineRoutingApi.create(requireContext(), BuildConfig.ROUTING_API_KEY)
  2. Build and perform the route request. The request requires departure and destination coordinates. You can also provide additional parameters. Add them all using the RoutingOptions class, which you can then use to perform the routing request. As with the legacy SDK, routing results are returned in the provided callback - RoutingCallback.

    1private fun planRoute(
    2 departureCoordinate: GeoCoordinate,
    3 destinationCoordinate: GeoCoordinate
    4) {
    5 val routingOptions =
    6 RoutingOptions.Builder(Itinerary(departureCoordinate, destinationCoordinate))
    7 .routeType(RouteType.FAST)
    8 .considerTraffic(true)
    9 .build()
    10
    11 routingApi.planRoute(
    12 routingOptions,
    13 object : RoutingCallback {
    14 override fun onError(error: RoutingError) {
    15 Toast.makeText(requireContext(), error.message, Toast.LENGTH_SHORT).show()
    16 }
    17
    18 override fun onSuccess(result: RoutingResult) {
    19 val route = result.routes.firstOrNull() ?: return
    20 drawRoute(route)
    21 }
    22 }
    23 )
    24}
  3. Use the result of the call to draw a route on the map. To do this, get the list of coordinates of the route that you want to draw. Use the list to build a RouteOptions object. This is also the place to specify visual properties for the route. Then add the RouteOptions to the TomTomMap. When you display all of the routes, you can also specify the padding from the edges of the map.

    1val routeOptions = RouteOptions(
    2 geometry = route.geometry,
    3 color = Color.RED,
    4 destinationMarkerVisible = true,
    5 departureMarkerVisible = true,
    6)
    7tomTomMap.addRoute(routeOptions)
    8tomTomMap.zoomToRoutes(40)

Adding a route