> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/android/java/llms.txt)

# Directions route profiles

Your browser doesn't support HTML5 video. Open [link to the video](https://docs.mapbox.com/android/android/assets/medias/example-directions-profile-toggle-activity-e2d56163a043130ab3c832c824c8123a.mp4).

> **Note**
> 
> This example is a part of the [Mapbox Android Demo app](https://github.com/mapbox/mapbox-android-demo). You can find the values for all referenced resources in the [`res`](https://github.com/mapbox/mapbox-android-demo/tree/master/MapboxAndroidDemo/src/main/res) directory. For example, see [`res/values/activity_strings.xml`](https://github.com/mapbox/mapbox-android-demo/tree/master/MapboxAndroidDemo/src/main/res/values/activity_strings.xml) for `R.string.*` references used in this example. The dependencies can be found [here.](https://github.com/mapbox/mapbox-navigation-android-examples/blob/main/app/build.gradle) The examples use View binding. [See setup documention if necessary.](https://developer.android.com/topic/libraries/view-binding)

> **Note: Directions API pricing**
> 
> Products used within the Mapbox Java SDK, including the Directions API, are individually billed. For pricing information, see the documentation for the [Directions API](https://docs.mapbox.com/api/navigation/directions/#directions-api-pricing).

Title: `activity_javaservices_directions_profile_toggle`

[View on GitHub](https://github.com/mapbox/mapbox-android-demo/tree/master/MapboxAndroidDemo/src/main/res/layout/activity_javaservices_directions_profile_toggle.xml)

```xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:mapbox="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".examples.javaservices.DirectionsProfileToggleActivity">

    <com.mapbox.mapboxsdk.maps.MapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        mapbox:mapbox_cameraTargetLat="19.42777430539"
        mapbox:mapbox_cameraTargetLng="-99.1523793414"
        mapbox:mapbox_cameraZoom="11.7" />

    <Button
        android:id="@+id/driving_profile_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="32dp"
        android:background="@color/mapboxPurple"
        android:padding="8dp"
        android:textAllCaps="false"
        android:textStyle="normal"
        mapbox:layout_constraintBottom_toBottomOf="parent"
        mapbox:layout_constraintEnd_toStartOf="@+id/walking_profile_button"
        mapbox:layout_constraintHorizontal_bias="0.5"
        mapbox:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/walking_profile_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/mapboxPurple"
        android:padding="8dp"
        android:textAllCaps="false"
        android:textStyle="normal"
        mapbox:layout_constraintBottom_toBottomOf="@+id/driving_profile_button"
        mapbox:layout_constraintEnd_toStartOf="@+id/cycling_profile_button"
        mapbox:layout_constraintHorizontal_bias="0.5"
        mapbox:layout_constraintStart_toEndOf="@+id/driving_profile_button" />

    <Button
        android:id="@+id/cycling_profile_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/mapboxPurple"
        android:padding="8dp"
        android:textAllCaps="false"
        android:textStyle="normal"
        mapbox:layout_constraintBottom_toBottomOf="@+id/driving_profile_button"
        mapbox:layout_constraintEnd_toEndOf="parent"
        mapbox:layout_constraintHorizontal_bias="0.5"
        mapbox:layout_constraintStart_toEndOf="@+id/walking_profile_button" />

</androidx.constraintlayout.widget.ConstraintLayout>
```

**Java**

Title: `DirectionsProfileToggleActivity.java`

[View on GitHub](https://github.com/mapbox/mapbox-android-demo/tree/master/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/DirectionsProfileToggleActivity.java)

```java
package com.mapbox.mapboxandroiddemo.examples.javaservices;

import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.mapbox.api.directions.v5.DirectionsCriteria;
import com.mapbox.api.directions.v5.MapboxDirections;
import com.mapbox.api.directions.v5.models.DirectionsResponse;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.LineString;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxandroiddemo.R;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.LineLayer;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.utils.BitmapUtils;

import java.util.concurrent.TimeUnit;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import timber.log.Timber;

import static com.mapbox.core.constants.Constants.PRECISION_6;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOffset;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineCap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineJoin;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth;

/**
 * Use the Mapbox Java SDK to request directions from the Mapbox Directions API
 * and show the various directions profile.
 */
public class DirectionsProfileToggleActivity extends AppCompatActivity
    implements MapboxMap.OnMapClickListener {

  private static final String TAG = "DirectionsProfileToggleActivity";
  private static final String ROUTE_LAYER_ID = "route-layer-id";
  private static final String ROUTE_SOURCE_ID = "route-source-id";
  private static final String ICON_LAYER_ID = "icon-layer-id";
  private static final String ICON_SOURCE_ID = "icon-source-id";
  private static final String RED_PIN_ICON_ID = "red-pin-icon-id";
  private MapView mapView;
  private MapboxMap mapboxMap;
  private DirectionsRoute drivingRoute;
  private DirectionsRoute walkingRoute;
  private DirectionsRoute cyclingRoute;
  private MapboxDirections client;
  private Point origin = Point.fromLngLat(-99.13037323366, 19.40488375253);
  private Point destination = Point.fromLngLat(-99.167663574, 19.426984786987);
  private String lastSelectedDirectionsProfile = DirectionsCriteria.PROFILE_DRIVING;
  private Button drivingButton;
  private Button walkingButton;
  private Button cyclingButton;
  private boolean firstRouteDrawn = false;
  private String[] profiles = new String[]{
    DirectionsCriteria.PROFILE_DRIVING,
    DirectionsCriteria.PROFILE_CYCLING,
    DirectionsCriteria.PROFILE_WALKING
  };

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Mapbox access token is configured here. This needs to be called either in your application
    // object or in the same activity which contains the mapview.
    Mapbox.getInstance(this, getString(R.string.access_token));

    // This contains the MapView in XML and needs to be called after the access token is configured.
    setContentView(R.layout.activity_javaservices_directions_profile_toggle);

    drivingButton = findViewById(R.id.driving_profile_button);
    drivingButton.setTextColor(Color.WHITE);
    walkingButton = findViewById(R.id.walking_profile_button);
    cyclingButton = findViewById(R.id.cycling_profile_button);

    // Setup the MapView
    mapView = findViewById(R.id.mapView);
    mapView.onCreate(savedInstanceState);
    mapView.getMapAsync(new OnMapReadyCallback() {
      @Override
      public void onMapReady(@NonNull MapboxMap mapboxMap) {
        mapboxMap.setStyle(Style.MAPBOX_STREETS, new Style.OnStyleLoaded() {
          @Override
          public void onStyleLoaded(@NonNull Style style) {

            DirectionsProfileToggleActivity.this.mapboxMap = mapboxMap;

            initSource(style);

            initLayers(style);

            getAllRoutes(false);

            initButtonClickListeners();

            mapboxMap.addOnMapClickListener(DirectionsProfileToggleActivity.this);

            Toast.makeText(DirectionsProfileToggleActivity.this,
                R.string.instruction, Toast.LENGTH_SHORT).show();
          }
        });
      }
    });
  }

  /**
   * Load route info for each Directions API profile.
   *
   * @param fromMapClick whether the route loading is being triggered from tapping
   *                     on the map
   */
  private void getAllRoutes(boolean fromMapClick) {
    for (String profile : profiles) {
      getSingleRoute(profile, fromMapClick);
    }
  }

  @Override
  public boolean onMapClick(@NonNull LatLng point) {
    destination = Point.fromLngLat(point.getLongitude(), point.getLatitude());
    moveDestinationMarkerToNewLocation(point);
    getAllRoutes(true);
    return true;
  }

  /**
   * Move the destination marker to wherever the map was tapped on.
   *
   * @param pointToMoveMarkerTo where the map was tapped on
   */
  private void moveDestinationMarkerToNewLocation(LatLng pointToMoveMarkerTo) {
    mapboxMap.getStyle(new Style.OnStyleLoaded() {
      @Override
      public void onStyleLoaded(@NonNull Style style) {
        GeoJsonSource destinationIconGeoJsonSource = style.getSourceAs(ICON_SOURCE_ID);
        if (destinationIconGeoJsonSource != null) {
          destinationIconGeoJsonSource.setGeoJson(Feature.fromGeometry(Point.fromLngLat(
              pointToMoveMarkerTo.getLongitude(), pointToMoveMarkerTo.getLatitude())));
        }
      }
    });
  }

  /**
   * Add the source for the Directions API route line LineLayer.
   */
  private void initSource(@NonNull Style loadedMapStyle) {
    loadedMapStyle.addSource(new GeoJsonSource(ROUTE_SOURCE_ID));
    GeoJsonSource iconGeoJsonSource = new GeoJsonSource(ICON_SOURCE_ID,
        Feature.fromGeometry(Point.fromLngLat(destination.longitude(),
            destination.latitude())));
    loadedMapStyle.addSource(iconGeoJsonSource);
  }

  /**
   * Set up the click listeners on the buttons for each Directions API profile.
   */
  private void initButtonClickListeners() {
    drivingButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        drivingButton.setTextColor(Color.WHITE);
        walkingButton.setTextColor(Color.BLACK);
        cyclingButton.setTextColor(Color.BLACK);
        lastSelectedDirectionsProfile = DirectionsCriteria.PROFILE_DRIVING;
        showRouteLine();
      }
    });
    walkingButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        drivingButton.setTextColor(Color.BLACK);
        walkingButton.setTextColor(Color.WHITE);
        cyclingButton.setTextColor(Color.BLACK);
        lastSelectedDirectionsProfile = DirectionsCriteria.PROFILE_WALKING;
        showRouteLine();
      }
    });
    cyclingButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        drivingButton.setTextColor(Color.BLACK);
        walkingButton.setTextColor(Color.BLACK);
        cyclingButton.setTextColor(Color.WHITE);
        lastSelectedDirectionsProfile = DirectionsCriteria.PROFILE_CYCLING;
        showRouteLine();
      }
    });
  }

  /**
   * Display the Directions API route line depending on which profile was last
   * selected.
   */
  private void showRouteLine() {
    if (mapboxMap != null) {
      mapboxMap.getStyle(new Style.OnStyleLoaded() {
        @Override
        public void onStyleLoaded(@NonNull Style style) {

          // Retrieve and update the source designated for showing the directions route
          GeoJsonSource routeLineSource = style.getSourceAs(ROUTE_SOURCE_ID);

          // Create a LineString with the directions route's geometry and
          // reset the GeoJSON source for the route LineLayer source
          if (routeLineSource != null) {
            switch (lastSelectedDirectionsProfile) {
              case DirectionsCriteria.PROFILE_DRIVING:
                routeLineSource.setGeoJson(LineString.fromPolyline(drivingRoute.geometry(),
                    PRECISION_6));
                break;
              case DirectionsCriteria.PROFILE_WALKING:
                routeLineSource.setGeoJson(LineString.fromPolyline(walkingRoute.geometry(),
                    PRECISION_6));
                break;
              case DirectionsCriteria.PROFILE_CYCLING:
                routeLineSource.setGeoJson(LineString.fromPolyline(cyclingRoute.geometry(),
                    PRECISION_6));
                break;
              default:
                break;
            }
          }
        }
      });
    }
  }

  /**
   * Add the route and icon layers to the map
   */
  private void initLayers(@NonNull Style loadedMapStyle) {
    LineLayer routeLayer = new LineLayer(ROUTE_LAYER_ID, ROUTE_SOURCE_ID);

    // Add the LineLayer to the map. This layer will display the directions route.
    routeLayer.setProperties(
        lineCap(Property.LINE_CAP_ROUND),
        lineJoin(Property.LINE_JOIN_ROUND),
        lineWidth(5f),
        lineColor(Color.parseColor("#006eff"))
    );
    loadedMapStyle.addLayer(routeLayer);

    // Add the red marker icon image to the map
    loadedMapStyle.addImage(RED_PIN_ICON_ID, BitmapUtils.getBitmapFromDrawable(
        getResources().getDrawable(R.drawable.red_marker)));

    // Add the red marker icon SymbolLayer to the map
    loadedMapStyle.addLayer(new SymbolLayer(ICON_LAYER_ID, ICON_SOURCE_ID).withProperties(
        iconImage(RED_PIN_ICON_ID),
        iconIgnorePlacement(true),
        iconAllowOverlap(true),
        iconOffset(new Float[]{0f, -9f})));
  }

  /**
   * Make a request to the Mapbox Directions API. Once successful, pass the route to the
   * route layer.
   *
   * @param profile the directions profile to use in the Directions API request
   */
  private void getSingleRoute(String profile, boolean fromMapClick) {
    client = MapboxDirections.builder()
        .origin(origin)
        .destination(destination)
        .overview(DirectionsCriteria.OVERVIEW_FULL)
        .profile(profile)
        .accessToken(getString(R.string.access_token))
        .build();

    client.enqueueCall(new Callback<DirectionsResponse>() {
      @Override
      public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
        // You can get the generic HTTP info about the response
        Timber.d("Response code: " + response.code());
        if (response.body() == null) {
          Timber.e("No routes found, make sure you set the right user and access token.");
          return;
        } else if (response.body().routes().size() < 1) {
          Timber.e("No routes found");
          return;
        }

        switch (profile) {
          case DirectionsCriteria.PROFILE_DRIVING:
            drivingRoute = response.body().routes().get(0);
            drivingButton.setText(String.format(getString(R.string.driving_profile),
                String.valueOf(TimeUnit.SECONDS.toMinutes(drivingRoute.duration().longValue()))));
            if (!firstRouteDrawn) {
              showRouteLine();
              firstRouteDrawn = true;
            }
            break;
          case DirectionsCriteria.PROFILE_WALKING:
            walkingRoute = response.body().routes().get(0);
            walkingButton.setText(String.format(getString(R.string.walking_profile),
                String.valueOf(TimeUnit.SECONDS
                    .toMinutes(walkingRoute.duration().longValue()))));
            break;
          case DirectionsCriteria.PROFILE_CYCLING:
            cyclingRoute = response.body().routes().get(0);
            cyclingButton.setText(String.format(getString(R.string.cycling_profile),
                String.valueOf(TimeUnit.SECONDS
                    .toMinutes(cyclingRoute.duration().longValue()))));
            break;
          default:
            break;
        }
        if (fromMapClick) {
          showRouteLine();
        }
      }

      @Override
      public void onFailure(Call<DirectionsResponse> call, Throwable throwable) {
        Timber.e("Error: " + throwable.getMessage());
        Toast.makeText(DirectionsProfileToggleActivity.this,
            "Error: " + throwable.getMessage(),
            Toast.LENGTH_SHORT).show();
      }
    });
  }

  @Override
  public void onResume() {
    super.onResume();
    mapView.onResume();
  }

  @Override
  protected void onStart() {
    super.onStart();
    mapView.onStart();
  }

  @Override
  protected void onStop() {
    super.onStop();
    mapView.onStop();
  }

  @Override
  public void onPause() {
    super.onPause();
    mapView.onPause();
  }

  @Override
  protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    mapView.onSaveInstanceState(outState);
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    // Cancel the Directions API request
    if (client != null) {
      client.cancelCall();
    }
    if (mapboxMap != null) {
      mapboxMap.removeOnMapClickListener(this);
    }
    mapView.onDestroy();
  }

  @Override
  public void onLowMemory() {
    super.onLowMemory();
    mapView.onLowMemory();
  }
}
```