Stay organized with collections
Save and categorize content based on your preferences.
You can customize elements of the navigation user interface and the map, and
add custom markers to the map. Refer to the Policies
page for guidelines on
acceptable modifications to the Navigation UI.
See the code
< > Show/Hide the Java code
for the navigation activity.
package com.example.navsdkcustomization;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.google.android.libraries.navigation.Camera;
import com.google.android.libraries.navigation.LatLng;
import com.google.android.libraries.navigation.ListenableResultFuture;
import com.google.android.libraries.navigation.Marker;
import com.google.android.libraries.navigation.MarkerOptions;
import com.google.android.libraries.navigation.NavigationApi;
import com.google.android.libraries.navigation.NavigationFragment;
import com.google.android.libraries.navigation.NavigationMap;
import com.google.android.libraries.navigation.Navigator;
import com.google.android.libraries.navigation.SimulationOptions;
import com.google.android.libraries.navigation.StylingOptions;
import com.google.android.libraries.navigation.Waypoint;
/**
* An activity that displays a map and a customized navigation UI.
*/
public class NavigationActivityCustomization extends AppCompatActivity {
private static final String TAG = NavigationActivityCustomization.class.getSimpleName();
private Navigator mNavigator;
private NavigationFragment mNavFragment;
private NavigationMap mMap;
// Define the Sydney Opera House by specifying its place ID.
private static final String SYDNEY_OPERA_HOUSE = "ChIJ3S-JXmauEmsRUcIaWtf4MzE";
// Set fields for requesting location permission.
private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
private boolean mLocationPermissionGranted;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize the Navigation SDK.
initializeNavigationSdk();
}
/**
* Starts the Navigation SDK and sets the camera to follow the device's location.
* Calls the navigateToPlace() method when the navigator is ready.
*/
private void initializeNavigationSdk() {
/*
* Request location permission, so that we can get the location of the
* device. The result of the permission request is handled by a callback,
* onRequestPermissionsResult.
*/
if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mLocationPermissionGranted = true;
} else {
ActivityCompat.requestPermissions(this,
new String[] { android.Manifest.permission.ACCESS_FINE_LOCATION },
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
}
if (!mLocationPermissionGranted) {
displayMessage("Error loading Navigation SDK: "
+ "The user has not granted location permission.");
return;
}
// Get a navigator.
NavigationApi.getNavigator(this, new NavigationApi.NavigatorListener() {
/**
* Sets up the navigation UI when the navigator is ready for use.
*/
@Override
public void onNavigatorReady(Navigator navigator) {
displayMessage("Navigator ready.");
mNavigator = navigator;
mNavFragment = (NavigationFragment) getFragmentManager()
.findFragmentById(R.id.navigation_fragment);
// Navigate to a place, specified by Place ID.
navigateToPlace(SYDNEY_OPERA_HOUSE);
}
/**
* Handles errors from the Navigation SDK.
* @param errorCode The error code returned by the navigator.
*/
@Override
public void onError(@NavigationApi.ErrorCode int errorCode) {
switch (errorCode) {
case NavigationApi.ErrorCode.NOT_AUTHORIZED:
displayMessage("Error loading Navigation SDK: Your API key is "
+ "invalid or not authorized to use the Navigation SDK.");
break;
case NavigationApi.ErrorCode.TERMS_NOT_ACCEPTED:
displayMessage("Error loading Navigation SDK: User did not accept "
+ "the Navigation Terms of Use.");
break;
case NavigationApi.ErrorCode.NETWORK_ERROR:
displayMessage("Error loading Navigation SDK: Network error.");
break;
case NavigationApi.ErrorCode.LOCATION_PERMISSION_MISSING:
displayMessage("Error loading Navigation SDK: Location permission "
+ "is missing.");
break;
default:
displayMessage("Error loading Navigation SDK: " + errorCode);
}
}
});
}
/**
* Customizes the navigation UI and the map.
*/
private void customizeNavigationUI() {
// Set custom colors for the navigator.
mNavFragment.setStylingOptions(new StylingOptions()
.primaryDayModeThemeColor(0xff1A237E)
.secondaryDayModeThemeColor(0xff3F51B5)
.primaryNightModeThemeColor(0xff212121)
.secondaryNightModeThemeColor(0xff424242)
.headerLargeManeuverIconColor(0xffffff00)
.headerSmallManeuverIconColor(0xffffa500)
.headerNextStepTypefacePath("/system/fonts/NotoSerif-BoldItalic.ttf")
.headerNextStepTextColor(0xff00ff00)
.headerNextStepTextSize(20f)
.headerDistanceTypefacePath("/system/fonts/NotoSerif-Italic.ttf")
.headerDistanceValueTextColor(0xff00ff00)
.headerDistanceUnitsTextColor(0xff0000ff)
.headerDistanceValueTextSize(20f)
.headerDistanceUnitsTextSize(18f)
.headerInstructionsTypefacePath("/system/fonts/NotoSerif-BoldItalic.ttf")
.headerInstructionsTextColor(0xffffff00)
.headerInstructionsFirstRowTextSize(24f)
.headerInstructionsSecondRowTextSize(20f)
.headerGuidanceRecommendedLaneColor(0xffffa500));
// Get the map.
mMap = mNavFragment.getMap();
// Turn off the traffic layer on the map.
mMap.setTrafficEnabled(false);
// Place a marker at the final destination.
if (mNavigator.getCurrentRouteSegment() != null) {
LatLng destinationLatLng = mNavigator.getCurrentRouteSegment()
.getDestinationLatLng();
Bitmap destinationMarkerIcon = BitmapFactory.decodeResource(
getResources(), R.drawable.ic_person_pin_48dp);
mMap.addMarker(new MarkerOptions()
.position(destinationLatLng)
.icon(destinationMarkerIcon)
.title("Destination marker"));
// Listen for a tap on the marker.
mMap.setOnMarkerClickListener(new NavigationMap.OnMarkerClickListener() {
@Override
public void onMarkerClick(Marker marker) {
displayMessage("Marker tapped: "
+ marker.getTitle() + ", at location "
+ marker.getPosition().latitude + ", "
+ marker.getPosition().longitude);
}
});
}
// Set the camera to follow the device location with 'TILTED' driving view.
mNavFragment.getCamera().followMyLocation(Camera.Perspective.TILTED);
}
/**
* Requests directions from the user's current location to a specific place (provided
* by the Google Places API).
*/
private void navigateToPlace(String placeId) {
Waypoint destination;
try {
destination = Waypoint.fromPlaceId(placeId, null);
} catch (Waypoint.UnsupportedPlaceIdException e) {
displayMessage("Error starting navigation: Place ID is not supported.");
return;
}
// Create a future to await the result of the asynchronous navigator task.
ListenableResultFuture<Navigator.RouteStatus> pendingRoute =
mNavigator.setDestination(destination);
// Define the action to perform when the SDK has determined the route.
pendingRoute.setOnResultListener(
new ListenableResultFuture.OnResultListener<Navigator.RouteStatus>() {
@Override
public void onResult(Navigator.RouteStatus code) {
switch (code) {
case OK:
// Hide the toolbar to maximize the navigation UI.
if (getActionBar() != null) {
getActionBar().hide();
}
// Customize the navigation UI.
customizeNavigationUI();
// Enable voice audio guidance (through the device speaker).
mNavigator.setAudioGuidance(
Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE);
// Simulate vehicle progress along the route for demo/debug builds.
if (BuildConfig.DEBUG) {
mNavigator.getSimulator().simulateLocationsAlongExistingRoute(
new SimulationOptions().speedMultiplier(5));
}
// Start turn-by-turn guidance along the current route.
mNavigator.startGuidance();
break;
// Handle error conditions returned by the navigator.
case NO_ROUTE_FOUND:
displayMessage("Error starting navigation: No route found.");
break;
case NETWORK_ERROR:
displayMessage("Error starting navigation: Network error.");
break;
case ROUTE_CANCELED:
displayMessage("Error starting navigation: Route canceled.");
break;
default:
displayMessage("Error starting navigation: "
+ String.valueOf(code));
}
}
});
}
/**
* Handles the result of the request for location permissions.
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
@NonNull int[] grantResults) {
mLocationPermissionGranted = false;
switch (requestCode) {
case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
// If request is canceled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mLocationPermissionGranted = true;
}
}
}
}
/**
* Shows a message on screen and in the log. Used when something goes wrong.
* @param errorMessage The message to display.
*/
private void displayMessage(String errorMessage) {
Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
Log.d(TAG, errorMessage);
}
}
Primary day mode - the daytime color of the navigation header
Secondary day mode - the daytime color of the next-turn indicator
Primary night mode - the nighttime color of the navigation header
Secondary night mode - the nighttime color of the next-turn indicator
Text elements for instructions
Text color
Font
Text size of the first row
Text size of the second row
Text elements for next steps
Font
Text color of the distance value
Text size of the distance value
Text color of the distance units
Text size of the distance units
Maneuver icons
Color of the large maneuver icon
Color of the small maneuver icon
Lane guidance
Color of the recommended lane or lanes
The following example shows how to set styling options:
private NavigationFragment mNavFragment;
mNavFragment = (NavigationFragment) getFragmentManager()
.findFragmentById(R.id.navigation_fragment);
// Set the styling options on the fragment.
mNavFragment.setStylingOptions(new StylingOptions()
.primaryDayModeThemeColor(0xff1A237E)
.secondaryDayModeThemeColor(0xff3F51B5)
.primaryNightModeThemeColor(0xff212121)
.secondaryNightModeThemeColor(0xff424242)
.headerLargeManeuverIconColor(0xffffff00)
.headerSmallManeuverIconColor(0xffffa500)
.headerNextStepTypefacePath("/system/fonts/NotoSerif-BoldItalic.ttf")
.headerNextStepTextColor(0xff00ff00)
.headerNextStepTextSize(20f)
.headerDistanceTypefacePath("/system/fonts/NotoSerif-Italic.ttf")
.headerDistanceValueTextColor(0xff00ff00)
.headerDistanceUnitsTextColor(0xff0000ff)
.headerDistanceValueTextSize(20f)
.headerDistanceUnitsTextSize(18f)
.headerInstructionsTypefacePath("/system/fonts/NotoSerif-BoldItalic.ttf")
.headerInstructionsTextColor(0xffffff00)
.headerInstructionsFirstRowTextSize(24f)
.headerInstructionsSecondRowTextSize(20f)
.headerGuidanceRecommendedLaneColor(0xffffa500));
Turn the traffic layer off
Use NavigationMap.setTrafficEnabled() to enable or
disable the traffic layer on the map. This setting affects the indications of
traffic density shown on the map as a whole, but it does not affect the traffic
indications on the route plotted by the navigator.
private NavigationMap mMap;
// Get the map.
mMap = mNavFragment.getMap();
// Turn off the traffic layer on the map.
mMap.setTrafficEnabled(false);
Add custom markers
You can add custom markers to the map, to indicate points of interest for your
application or users. For example, you may want to indicate the pickup point at
the end of the route. Use NavigationMap.addMarker() to add a
marker, and NavigationMap.setOnMarkerClickListener()
to listen for taps on a marker.
The code below uses an icon stored in the project's
drawable resources, R.drawable.ic_person_pin_48dp. You
can use any image that suits your app.
// Place a marker at the final destination.
if (mNavigator.getCurrentRouteSegment() != null) {
LatLng destinationLatLng = mNavigator.getCurrentRouteSegment()
.getDestinationLatLng();
Bitmap destinationMarkerIcon = BitmapFactory.decodeResource(
getResources(), R.drawable.ic_person_pin_48dp);
mMap.addMarker(new MarkerOptions()
.position(destinationLatLng)
.icon(destinationMarkerIcon)
.title("Destination marker"));
// Listen for a tap on the marker.
mMap.setOnMarkerClickListener(new NavigationMap.OnMarkerClickListener() {
@Override
public void onMarkerClick(Marker marker) {
displayMessage("Marker tapped: "
+ marker.getTitle() + ", at location "
+ marker.getPosition().latitude + ", "
+ marker.getPosition().longitude);
}
});
}
You can specify a custom image as the marker; but, the SDK doesn’t
currently support labeling these images with text. For more information, see
Customizing Markers.
Floating text
You can add floating text anywhere in your app, as long as the Google
attribution isn’t covered. The Navigation SDK doesn’t support anchoring the
text to a latitude/longitude on the map, or to a label. For more information,
see Info windows.
AUTO Lets the Navigation SDK determine the
appropriate mode according to the device location and local time.
FORCE_NIGHT forces night mode on.
FORCE_DAY forces day mode on.
The following example shows forcing night mode to turn on within a navigation
fragment:
// Force night mode on.
mNavFragment.setForceNightMode(FORCE_NIGHT);
Display directions list
First, create the view and add it to your hierarchy.
setupDirectionsListView(){
// Create the view.
DirectionsListView directionsListView = new DirectionsListView(getApplicationContext());
// Add the view to your view hierarchy.
ViewGroup group = findViewById(R.id.directions_view);
group.addView(directionsListView);
// Add a button to your layout to close the directions list view.
ImageButton button = findViewById(R.id.close_directions_button); // this button is part of the container we hide in the next line.
button.setOnClickListener(
v -> findViewById(R.id.directions_view_container).setVisibility(View.GONE));
}
Be sure to forward life cycle events to the DirectionsListView just like they
are with NaviagtionView. For example:
When the user interface becomes cluttered with too much information, you can
reduce clutter by displaying fewer alternate routes than the default (two), or
by displaying no alternate routes at all. You can configure this option before
you fetch the routes by calling the RoutingOptions.alternateRoutesStrategy()
method with one of the following enumeration values:
Enumeration Value
Description
AlternateRoutesStrategy.SHOW_ALL
Default. Displays up to two alternate routes.
AlternateRoutesStrategy.SHOW_ONE
Displays one alternate route (if one is available).
AlternateRoutesStrategy.SHOW_NONE
Hides alternate routes.
Example
The following code example demonstrates how to hide alternate routes altogether.
RoutingOptions routingOptions = new RoutingOptions();
routingOptions.alternateRoutesStrategy(AlternateRoutesStrategy.SHOW_NONE);
navigator.setDestinations(destinations, routingOptions, displayOptions);