Sorry about the red box, but we really need you to update your browser. Read this excellent article if you're wondering why we are no longer supporting this browser version. Go to Browse Happy for browser suggestions and how to update.

Retrieving the estimated travel time, distance, and departure time

You can create an app 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 app that provides the BlackBerry device user with the estimated time of arrival at a friend's location. You could also create an app 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().

Code sample: Retrieving the estimated travel time and distance

You can create an app that retrieves the estimated time and distance it takes to travel between two locations. In the following steps, a UI application is created 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 a field to display the results.

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

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;

//Create the application framework by extending the UiApplication class. 
//In main(), create an instance of the new class and invoke 
//enterEventDispatcher() to enable the app to receive events. 
//In the application constructor, invoke pushScreen() to display the custom 
//screen for the app. The TravelTimeScreen class 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());
    }
}

//Create the framework for the custom screen by extending the MainScreen class.  
class TravelTimeScreen extends MainScreen implements FieldChangeListener
{
    private BasicEditField _destinationField;
    private LabelField _timeLabel;
    private LabelField _distanceLabel;
    private ButtonField travelButton;

//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 create a text field for the user to type 
//the destination in. Invoke add() to add the field to the screen. Create an 
//instance of the ButtonField class to create a button to retrieve the 
//travel time and distance estimate. Invoke Field.setChangeListener() 
//to listen for changes to the button. Invoke findTravelTime() to retrieve 
//the travel time and distance estimate when the user clicks the button. 
//Invoke add() to add the button to the screen. 
//Create instances of the LabelField class to display the travel 
//time and distance results.           
    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);
    }

//Create a method in the TravelTimeScreen class to provide the travel 
//time estimate. 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 fields.     
	   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("");

//Retrieve the geospatial coordinates for the starting and ending 
//locations, by first creating an instance of the Thread class in the findTravelTime 
//method that invokes run(). In run(), in a try/catch block, invoke Locator.geocode() 
//and pass as a parameter the destination String to find the address and return an 
//array of Landmark objects. Invoke Landmark.getQualifiedCoordinates() to retrieve 
//geospatial coordinates for the destination by using the geolocation service. 
//Invoke LocationProvider.getInstance() to retrieve a location provider to 
//request the current location. Invoke Location.getQualifiedCoordinates() to 
//retrieve the geospatial coordinates for the current location by using GPS. 
//Alternatively, if GPS is unavailable, you can use the geolocation service 
//to retrieve the coordinates for the current location.          
        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);

//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 starting 
//time. In this example, a synchrous request is made because a separate thread 
//was 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.  
                	   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();
    }

//In the showResults method, invoke invokeLater() to add this section of 
//code to the event queue of the app. 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 travel time and distance.       
    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);
            }
        });
    }
}