Voice generated directions in Android apps

Brad Leege
Tue, 10 May 2016 11:00:00 -0400

Add voice generated directions to your Android app using the Mapbox Android SDK, Mapbox Android Services, and the Android Speech To Text API.

To demonstrate how this works, we built an Android app called Go Where I Say that helps users find their way around the city of Seattle. Users generate local directions based on their starting point, Pike Place Market, by saying their destination, for example “Space Needle”.

Assembling the pieces

The app makes use of the Android SpeechRecognizer, which has been supported universally in AOSP since API 8, to turn the user’s voice command into a String. From there, we’re able to use the Mapbox Geocoding API (via Mapbox Android Services) to turn this String into geo coordinates called GeocodingFeature.

    // Use MapboxGeocoding To Get Geo Coordinates For String From SpeechRecognizer
    String speechText = "Space Needle";
    // Starting Place at Pike Place Market to give Geocoder context for producing local results
    LatLng pikePlace = new LatLng(47.60865, -122.34052);

    MapboxGeocoding geocodingClient = new MapboxGeocoding.Builder()
                .setAccessToken(getString(R.string.mapbox_access_token))
                .setLocation(speechText)
                .setProximity(Position.fromCoordinates(pikePlace.getLongitude(), pikePlace.getLatitude()))
                .build();

    geocodingClient.enqueueCall(new Callback<GeocodingResponse>() {
        @Override
        public void onResponse(Call<GeocodingResponse> call, Response<GeocodingResponse> response) {
            GeocodingFeature spaceNeedleGeoData = response.body().getFeatures().get(0);
            // Now We Can Generate Directions
        }
    }

Now that we have the GeocodingFeature we can use it to generate directions using the Mapbox Directions API (again via Mapbox Android Services).

    // Use MapboxDirections To Get Directions Using GeocodingFeature
    final ArrayList<Position> points = new ArrayList<>();
    // Starting at Pike Place Market
    points.add(Position.fromCoordinates(pikePlace.getLongitude(), pikePlace.getLatitude()));
    // Ending at Space Needle
    points.add(spaceNeedleGeoData.asPosition());

    MapboxDirections directionsClient = new com.mapbox.services.directions.v5.MapboxDirections.Builder()
        .setAccessToken(getString(R.string.mapbox_access_token))
        .setCoordinates(points)
        .setProfile(DirectionsCriteria.PROFILE_DRIVING)
        .build();

    directionsClient.enqueueCall(new Callback<DirectionsResponse>() {
        @Override
        public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
            DirectionsRoute routeFromPikePlaceMarketToSpaceNeedle = response.body().getRoutes().get(0);
            // Use this data to draw the route!
        }
    }

Drawing the Route

From DirectionsRoute data we can draw the route by creating a LineString and then adding it the map.

    // MapboxMap
    MapboxMap mapboxMap = ...

    // show route
    PolylineOptions polylineOptions = new PolylineOptions();
    polylineOptions.color(ContextCompat.getColor(this, R.color.colorAccent));
    polylineOptions.alpha(0.5f);

    LineString lineString = LineString.fromPolyline(route.getGeometry(), Constants.OSRM_PRECISION_V5);
    List<Position> coordinates = lineString.getCoordinates();
    for (int lc = 0; lc < coordinates.size(); lc++) {
        polylineOptions.add(new LatLng(coordinates.get(lc).getLatitude(), coordinates.get(lc).getLongitude()));
    }

    polylineOptions.width(getResources().getDimension(R.dimen.line_width_route));
    mapboxMap.addPolyline(polylineOptions);

Route From Pike Place Market to the Space Needle

Getting started

The Mapbox Android SDK and Mapbox Android Services library can be combined in many different ways to power your app. Dive into the Go Where I Say source code for a closer look at how we’ve used them here. If you have questions about how to build location based apps or want to share what you’re working on, hit me up on Twitter @bradleege.