Skip to content

Truck Profile

In this guide you will learn how to compute a route based on the accessibility given by the physical characteristics of a truck, such as height, weight, length, width and number of axles, and then render the route on the map.

Setup

First, get an API key token, see the Getting Started guide.
Download the Maps & Navigation SDK for Android archive file

Download the TruckProfile project archive file or clone the project with Git

See the Configure Android Example guide.

Run the example

In Android Studio, from the File menu, select Sync Project with Gradle Files

Truck profile routing android example screenshot

Truck profile routing android example screenshot

Truck profile routing android example screenshot

An android device should be connected via USB cable.
Press SHIFT+F10 to compile, install and run the example on the android device.

How it works

Android example screenshot
You can open the MainActivity.kt file to see how the truck route is computed and rendered on the map based on the accessibility given by the physical characteristics of the truck.
 1private val routingService = RoutingService(
 2     onStarted = {
 3         progressBar.visibility = View.VISIBLE
 4     },
 5     onCompleted = { routes, errorCode, _ ->
 6         progressBar.visibility = View.GONE
 7         when (errorCode)
 8         {
 9             GemError.NoError ->
10             {
11                 routesList = routes
12                 SdkCall.execute { gemSurfaceView.mapView?.presentRoutes(
13                         routes = routes,
14                         displayBubble = true
15                     )
16                 }
17                 settingsButtons.visibility = View.VISIBLE
18             }
19             GemError.Cancel ->
20             {
21                 showDialog("The routing action was canceled.")
22             }
23             else ->
24             {
25                 // There was a problem at computing the routing operation.
26                 showDialog("Routing service error: ${GemError.getMessage(errorCode)}")
27             }
28         }
29     }
30)
A routing service is instantiated to compute and render the truck route.
The onStarted and onCompleted routing callbacks are overridden and implemented, to show, and then hide, respectively, the routing computation progress bar, which is useful for very slow devices, where the route computation may take long enough to be noticeable by the user.
When the route calculation is completed, if there is no error, the resulting routes (as there could be more than one alternate route in the resulting set between the specified departure and destination points) are drawn on the map:
gemSurfaceView.mapView?.presentRoutes()
Then the settings button is set to visible, so that the user can introduce the physical characteristics of the truck. Upon saving these, the route is computed again, in case it has to change to accomodate the updated characteristics of the truck, such as its dimensions and weight.
 1override fun onCreate(savedInstanceState: Bundle?)
 2{
 3     super.onCreate(savedInstanceState)
 4     setContentView(R.layout.activity_main)
 5     gemSurfaceView = findViewById(R.id.gem_surface_view)
 6     progressBar = findViewById(R.id.progress_bar)
 7     settingsButtons = findViewById<FloatingActionButton?>(R.id.settings_button).also {
 8         it.setOnClickListener {
 9             onSettingsButtonClicked()
10         }
11     }
12     SdkSettings.onMapDataReady = onMapDataReady@{ isReady ->
13         if (!isReady) return@onMapDataReady
14         // Defines an action that should be done when the world map is ready (Updated/ loaded).
15         SdkCall.execute {
16             waypoints = arrayListOf(
17                 Landmark("London", 51.5073204, -0.1276475),
18                 Landmark("Paris", 48.8566932, 2.3514616)
19             )
20             routingService.calculateRoute(waypoints)
21         }
22         gemSurfaceView.mapView?.onTouch = { xy ->
23             SdkCall.execute {
24                 // tell the map view where the touch event happened
25                 gemSurfaceView.mapView?.cursorScreenPosition = xy
26                 // get the visible routes at the touch event point
27                 val routes = gemSurfaceView.mapView?.cursorSelectionRoutes
28                 // check if there is any route
29                 if (!routes.isNullOrEmpty())
30                 {
31                     // set the touched route as the main route and center on it
32                     val route = routes[0]
33                     gemSurfaceView.mapView?.apply {
34                         preferences?.routes?.mainRoute = route
35                         centerOnRoutes(routesList)
36                     }
37                 }
38             }
39         }
40     }
41     SdkSettings.onApiTokenRejected = {
42         showDialog("TOKEN REJECTED")
43     }
44     if (!Util.isInternetConnected(this))
45     {
46         showDialog("You must be connected to the internet!")
47     }
48}
The onCreate() function is overridden in the MainActivity: AppCompatActivity() class, and checks if internet access is available, showing a dialog message if not.
findViewById() is used to obtain pointers to the various graphical user interface elements where text or graphical data is to be displayed.
A click listener is set for the settings button, to recompute the route when the user changes the physical parameters of the truck.
it.setOnClickListener { onSettingsButtonClicked() }
When the map is loaded and ready,
onMapDataReady@{}
the routing service instantiated and shown above is used to calculate the route between a list of 2 predefined waypoints where the first is the departure point and the second is the destination point:
routingService.calculateRoute(waypoints)
Each waypoint is a Landmark containing a name, a latitude, in degrees, and a longitude, in degrees:
Landmark("Paris", 48.8566932, 2.3514616)
The list of waypoints from which a route is calculated must have at least 2 elements, for the departure and destination, respectively, but can have more elements, for additional waypoints along the route. In this example there are 2 waypoints in the list.
A touch listener is defined
gemSurfaceView.mapView?.onTouch = { xy ->
and gemSurfaceView.mapView?.cursorSelectionRoutes is used to see if the user touched one or more routes on the map. If so, the first touched route (at index 0) is selected and set as the main route, which causes it to be drawn in dark blue on the map.
Then the camera centers on the bounding box containing all routes between the departure and destination points.
centerOnRoutes(routesList)
1private val adapter = TruckProfileSettingsAdapter(getInitialDataSet())
A variable in the class MainActivity : AppCompatActivity() is created to hold the truck dimensions and other attributes.
1private fun getInitialDataSet(): List<TruckProfileSettingsModel>
The getInitialDataSet() function sets the default initial values in the form with the truck dimensions and other attributes required for identifying a corresponding route between the given departure and destination which is navigable by the specified truck.
 1private fun onSettingsButtonClicked()
 2{
 3     val builder = AlertDialog.Builder(this)
 4     val convertView = layoutInflater.inflate(R.layout.truck_profile_settings_view, null)
 5     val listView = convertView.findViewById<RecyclerView>(R.id.truck_profile_settings_list).apply
 6     {
 7         layoutManager = LinearLayoutManager(this@MainActivity)
 8         addItemDecoration(DividerItemDecoration(applicationContext,
 9         (layoutManager as LinearLayoutManager).orientation))
10     }
11     listView.adapter = adapter
12     builder.setTitle(getString(R.string.app_name))
13     builder.setView(convertView)
14     builder.setNeutralButton(getString(R.string.save)) { dialog, _ ->
15         onSaveButtonClicked()
16         dialog.dismiss()
17     }
18     val dialog = builder.create()
19     dialog.show()
20}
The onSettingsButtonClicked() function is called by the listener defined in the onCreate() function above, when the user clicks the industrial wheel settings button to modify the truck profile attributes.
This function uses the adapter variable defined above to display the truck attribute values and enable the user to modify them, so they can then be used to find a route appropriate for the truck.
A save button is defined, which closes the dialog and calls the onSaveButtonClicked() function to calculate the route using the updated truck parameter values.
 1private fun onSaveButtonClicked()
 2{
 3     val dataSet = adapter.dataSet
 4     // convert m to cm
 5     val width = (dataSet[ETruckProfileSettings.Width.ordinal].currentDoubleValue * 100).toInt()
 6     val height = (dataSet[ETruckProfileSettings.Height.ordinal].currentDoubleValue * 100).toInt()
 7     val length = (dataSet[ETruckProfileSettings.Length.ordinal].currentDoubleValue * 100).toInt()
 8     // convert t to kg
 9     val weight = (dataSet[ETruckProfileSettings.Weight.ordinal].currentDoubleValue * 1000).toInt()
10     val axleWeight = (dataSet[ETruckProfileSettings.AxleWeight.ordinal].currentDoubleValue * 1000).toInt()
11     // convert km/h to m/s
12     val maxSpeed = dataSet[ETruckProfileSettings.MaxSpeed.ordinal].currentIntValue * 0.27778
13     SdkCall.execute {
14         routingService.apply {
15             preferences.alternativesSchema = ERouteAlternativesSchema.Never
16             preferences.transportMode = ERouteTransportMode.Lorry
17             preferences.truckProfile = TruckProfile(
18                 massKg = weight,
19                 heightCm = height,
20                 lengthCm = length,
21                 widthCm = width,
22                 axleLoadKg = axleWeight,
23                 maxSpeedMs = maxSpeed
24             )
25             calculateRoute(waypoints)
26         }
27     }
28}
The onSaveButtonClicked() function sets the truck profile attributes in the preferences and then calculates the route using
calculateRoute(waypoints)

Android Examples

Maps SDK for Android Examples can be downloaded or cloned with Git