Retrieving the estimated travel time, distance, and departure time

You can create an application that requests the estimated travel time, distance, and departure time for automobile travel in the United States and Canada by using the Travel Time API, which is provided in the net.rim.device.api.lbs.travel package. For example, you can create a social networking application that provides the BlackBerry device user with the estimated time of arrival at a friend's location. You could also create an application that integrates with a user's Calendar application to provide the user with a departure time for getting to an upcoming appointment.

TravelTimeEstimator is a singleton class that supports synchronous and asynchronous requests. Synchronous requests block processes on the current thread until the request returns or throws an exception. As a best practice, you should run synchronous calls on a separate thread, so that the request doesn't block the current thread. An asynchronous request returns to the thread after sending a request for an estimate. The results are returned asynchronously to a listener object that you provide.

Requests are sent to a travel time server, which uses current and historical traffic information to plot a route between the starting and ending locations. You can create a request for the travel time and distance by obtaining an instance of the TravelTimeEstimator class, invoking TravelTimeEstimator.requestArrivalEstimate() and passing in the geographic coordinates for the starting and ending locations, and the start time. When the request returns a TravelTime object, you can retrieve the travel time and distance by invoking TravelTime.getElapsedTime() and TravelTime.getDistance(), respectively. Requesting a departure time requires that you invoke TravelTimeEstimator.requestDepartureEstimate() and pass in the arrival time along with the coordinates for the starting and ending locations. When the request returns, you can retrieve the departure time by invoking TravelTime.getStartTime().

Retrieve the estimated travel time and distance

You can create an application that retrieves the estimated time and distance that it takes to travel between two locations. In the following steps, you create an application that contains a text field in which the BlackBerry device user types a destination address, a button that the user clicks to retrieve the estimated time and distance to reach the destination, and fields to display the results. The request for the estimated travel time and distance is sent synchronously.

Before you begin:

Make sure that the BlackBerry device or BlackBerry Smartphone Simulator has GPS enabled.

  1. Import the required classes and interfaces.
    import net.rim.device.api.lbs.maps.MapDimensions;
    import net.rim.device.api.lbs.maps.model.MapLocation;
    import net.rim.device.api.lbs.maps.model.MapPoint;
    import net.rim.device.api.lbs.maps.server.Geocoder;
    import net.rim.device.api.lbs.maps.server.exchange.GeocodeExchange;
    import net.rim.device.api.lbs.travel.TravelTime;
    import net.rim.device.api.lbs.travel.TravelTimeEstimator;
    import net.rim.device.api.system.Application;
    import net.rim.device.api.ui.Field;
    import net.rim.device.api.ui.FieldChangeListener;
    import net.rim.device.api.ui.UiApplication;
    import net.rim.device.api.ui.component.BasicEditField;
    import net.rim.device.api.ui.component.ButtonField;
    import net.rim.device.api.ui.component.Dialog;
    import net.rim.device.api.ui.component.LabelField;
    import net.rim.device.api.ui.component.TextField;
    import net.rim.device.api.ui.container.MainScreen;
    import java.util.Vector;
    import javax.microedition.location.Coordinates;
    import javax.microedition.location.LocationProvider;
  2. Create the application framework by extending the UiApplication class. In main(), create an instance of the new class and invoke enterEventDispatcher() to enable the application to receive events. In the application constructor, invoke pushScreen() to display the custom screen for the application. The TravelTimeScreen class, described in step 3, represents the custom screen.
    public final class TravelTimeDemo extends UiApplication
    {
        public static void main(String[] args)
        {
            TravelTimeDemo theApp = new TravelTimeDemo();
            theApp.enterEventDispatcher();
        }
        
        public TravelTimeDemo()
        {
            pushScreen(new TravelTimeScreen());
        }
    }
  3. Create the framework for the custom screen by extending the MainScreen class and implementing FieldChangeListener.
    class TravelTimeScreen extends MainScreen implements 
            FieldChangeListener
    {
        private BasicEditField _destinationField;
        private LabelField _timeLabel;
        private LabelField _distanceLabel;
        private ButtonField travelButton;
  4. In the constructor, invoke super() to create a default menu. Invoke setTitle() to specify the title for the screen. Create an instance of the BasicEditField class to provide a text field for the user to type the destination in. Add the field to the screen. Create and add instances of the LabelField class to display the travel time and distance results. Create an instance of the ButtonField class to create a button that retrieves travel time and distance estimate. Set a change listener on the button to listen for changes to the button, and add the button to the screen.
        public TravelTimeScreen()
        {
            super(DEFAULT_CLOSE | DEFAULT_MENU);
    
            setTitle("Travel Time Demo");
                         
            _destinationField = new BasicEditField("Destination: ", "", 500, 
                    TextField.NO_NEWLINE);
            add(_destinationField);
            
            _timeLabel = new LabelField();
            add(_timeLabel);
            
            _distanceLabel = new LabelField();
            add(_distanceLabel);
            
            travelButton = new ButtonField("Get Travel Estimate", 
                    ButtonField.CONSUME_CLICK);
            travelButton.setChangeListener(this);
            add(travelButton);
        }
  5. Override the fieldChanged method. This method includes functionality for retrieving the arrival time. Create an instance of the String class that invokes getText() to retrieve the destination that the user typed. Validate that the field is not empty by checking for a null value or for a length of 0 in the destination field. Clear the travel time and distance result field.
        public void fieldChanged(final Field field, int context)
        {
            final String destination = _destinationField.getText();
            if ((destination == null) || (destination.length() == 0))
            {
                Dialog.alert("Destination field cannot be empty");
                return;
            }
            
            _timeLabel.setText("");
            _distanceLabel.setText("");
  6. Retrieve the geospatial coordinates for the starting and ending locations, by first creating an instance of the Thread class that overrides run(). In run(), in a try/catch block, invoke LocationProvider.getInstance() to retrieve a location provider to request the current location. Invoke Location.getQualifiedCoordinates() to retrieve the geographic coordinates for the current location by using GPS.
            Thread travelTimeThread = new Thread()
            {
                public void run()
                {
                    try
                    {
                        LocationProvider provider = LocationProvider
                                .getInstance(null);
                    	
                        if (provider == null)
                        {
                            throw new IllegalStateException(
                                    "No LocationProvider available");
                        }
                        
                        Coordinates startCoords = provider.getLocation(-1)
                                .getQualifiedCoordinates();
  7. After you retrieve the current location with the GPS, create a new instance of MapPoint using the returned coordinates. The MapPoint object is necessary for providing geographic context with a geocoding request. Invoke Geocoder.getInstance().geocode() and pass in the MapPoint object for context, and the String that contains the address for the end location. Verify that the GeocodeExchange object that is returned is not null, and retrieve the Vector of results by invoking GeocodeExchange.getResults(). Retrieve the first result from the vector and cast it to a MapLocation object. In cases where more than one result is returned, the result in the first index is the one that is the most relevant to your request. Create a Coordinates object for the end location by using the MapLocation object.
                        MapPoint startPoint = new MapPoint(startCoords);                        
                        GeocodeExchange exchange = Geocoder.getInstance().geocode(
                              null, 
                              destination, 
                              new MapDimensions(startPoint,480, 360, 5, 0), 0);                   
                        
                        if(exchange.getExceptionList().size() < 0)
                        {
                        	   throw new IllegalStateException(
                                    "Can't find end coordinates.");
                        }
                        
                    	   Vector results = exchange.getResults();
                    	   MapLocation location = (MapLocation) results.elementAt(0);
                    	   Coordinates endCoords = new Coordinates(location.getLat(), 
                                location.getLon(), 0);
  8. Create an instance of the TravelTimeEstimator class by invoking TraveTimeEstimator.getInstance(). Invoke requestArrivalEstimate() to request the estimated travel time and distance. Specify the Coordinates objects for the starting and ending locations, and specify the departure time. In this example, a synchrous request is made because a separate thread was already created to retrieve the geospatial coordinates. You can use the TravelTime.START_NOW constant to indicate that travel starts immediately. Invoke showResults(), which is described in step 8, to display the results. Invoke start() to start the thread.
                        TravelTimeEstimator est = TravelTimeEstimator.getInstance();
                        final TravelTime travelTime = est.requestArrivalEstimate(
                                startCoords, endCoords, TravelTime.START_NOW, null);
                        showResults(travelTime);       
                    }
                    catch (final Exception e)
                    {
                        Dialog.alert(e.getMessage());
                    }
                }
            };
            travelTimeThread.start();
        }
  9. In the showResults method, call invokeLater() to add this section of code to the event queue of the application. Create an instance of the Runnable class and pass it as a parameter to invokeLater(). Override run() in the definition of Runnable. Invoke getElapsedTime() to retrieve the estimated travel time. Convert the returned travel time from milliseconds to an hour: minute: seconds format. Invoke getDistance() to retrieve the estimated travel distance. Convert the returned distances from meters to kilometers. Invoke setText() to display the results for the requests.
        private void showResults(final TravelTime travelTime)
        {
            Application.getApplication().invokeLater(new Runnable()
            {
                public void run()
                {
                    long value = travelTime.getElapsedTime() / 1000;
                    long seconds = value % 60;
                    value /= 60;
                    long minutes = value % 60;
                    long hours = value / 60;
    
                    StringBuffer buffer = new StringBuffer();
                    buffer.append(hours);
                    buffer.append(':');
                    if (minutes < 10)
                    {
                        buffer.append('0');
                    }
                    buffer.append(minutes);
                    buffer.append(':');
                    if (seconds < 10)
                    {
                        buffer.append('0');
                    }
                    buffer.append(seconds);
                    
                    String msg = "Travel Time (h:m:s): " + buffer.toString();
                    TravelTimeScreen.this._timeLabel.setText(msg);
                    
                    double distance = travelTime.getDistance() / 1000.0;
                    msg = "Distance (km): " + Double.toString(distance);
                    TravelTimeScreen.this._distanceLabel.setText(msg);
                }
            });
        }
    }
Back To Top

Code sample: Retrieving the estimated travel time and distance

import net.rim.device.api.lbs.maps.MapDimensions;
import net.rim.device.api.lbs.maps.model.MapLocation;
import net.rim.device.api.lbs.maps.model.MapPoint;
import net.rim.device.api.lbs.maps.server.Geocoder;
import net.rim.device.api.lbs.maps.server.exchange.GeocodeExchange;
import net.rim.device.api.lbs.travel.TravelTime;
import net.rim.device.api.lbs.travel.TravelTimeEstimator;
import net.rim.device.api.system.Application;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BasicEditField;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.TextField;
import net.rim.device.api.ui.container.MainScreen;
import java.util.Vector;
import javax.microedition.location.Coordinates;
import javax.microedition.location.LocationProvider;


public final class TravelTimeDemo extends UiApplication
{
    public static void main(String[] args)
    {
        TravelTimeDemo theApp = new TravelTimeDemo();
        theApp.enterEventDispatcher();
    }
    
    public TravelTimeDemo()
    {
        pushScreen(new TravelTimeScreen());
    }
}

class TravelTimeScreen extends MainScreen implements FieldChangeListener
{
    private BasicEditField _destinationField;
    private LabelField _timeLabel;
    private LabelField _distanceLabel;
    private ButtonField travelButton;
          
    public TravelTimeScreen()
    {
        super(DEFAULT_CLOSE | DEFAULT_MENU);

        setTitle("Travel Time Demo");
                     
        _destinationField = new BasicEditField("Destination: ", "", 500, 
                TextField.NO_NEWLINE);
        add(_destinationField);
        
        _timeLabel = new LabelField();
        add(_timeLabel);
        
        _distanceLabel = new LabelField();
        add(_distanceLabel);
        
        travelButton = new ButtonField("Get Travel Estimate",
                ButtonField.CONSUME_CLICK);
        travelButton.setChangeListener(this);
        add(travelButton);
    }
    
	   public void fieldChanged(final Field field, int context)
    {
        final String destination = _destinationField.getText();
        if ((destination == null) || (destination.length() == 0))
        {
            Dialog.alert("Destination field cannot be empty");
            return;
        }
        
        _timeLabel.setText("");
        _distanceLabel.setText("");
        
        Thread travelTimeThread = new Thread()
        {
            public void run()
            {
                try
                {
                    LocationProvider provider = LocationProvider.getInstance(null);
                	
                    if (provider == null)
                    {
                        throw new IllegalStateException("No LocationProvider 
                                available");
                    }
                    
                    Coordinates startCoords = provider.getLocation(-1)
                             .getQualifiedCoordinates();                   
                    MapPoint startPoint = new MapPoint(startCoords);                        
                    GeocodeExchange exchange = Geocoder.getInstance().geocode(null, 
                            destination, 
                            new MapDimensions(startPoint,480, 360, 5, 0), 0);                   
                    
                    if(exchange.getExceptionList().size() < 0)
                    {
                        throw new IllegalStateException("Can't find end 
                                coordinates.");
                    }
                    
                	   Vector results = exchange.getResults();
                	   MapLocation location = (MapLocation) results.elementAt(0);
                	   Coordinates endCoords = new Coordinates(location.getLat(), 
                            location.getLon(), 0);

                	   TravelTimeEstimator est = TravelTimeEstimator.getInstance();
                    final TravelTime travelTime = est.requestArrivalEstimate(
                            startCoords, endCoords, TravelTime.START_NOW, null);
                    showResults(travelTime);       
                }
                catch (final Exception e)
                {
                    Dialog.alert(e.getMessage());
                }
            }
        };
        travelTimeThread.start();
    }
      
    private void showResults(final TravelTime travelTime)
    {
        Application.getApplication().invokeLater(new Runnable()
        {
            public void run()
            {
                long value = travelTime.getElapsedTime() / 1000;
                long seconds = value % 60;
                value /= 60;
                long minutes = value % 60;
                long hours = value / 60;

                StringBuffer buffer = new StringBuffer();
                buffer.append(hours);
                buffer.append(':');
                if (minutes < 10)
                {
                    buffer.append('0');
                }
                buffer.append(minutes);
                buffer.append(':');
                if (seconds < 10)
                {
                    buffer.append('0');
                }
                buffer.append(seconds);
                
                String msg = "Travel Time (h:m:s): " + buffer.toString();
                TravelTimeScreen.this._timeLabel.setText(msg);
                
                double distance = travelTime.getDistance() / 1000.0;
                msg = "Distance (km): " + Double.toString(distance);
                TravelTimeScreen.this._distanceLabel.setText(msg);
            }
        });
    }
}
Back To Top
Previous topic: Navigation

Was this information helpful? Send us your comments.