/* * TravelTimeDemo.java * * Copyright � 1998-2011 Research In Motion Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Note: For the sake of simplicity, this sample application may not leverage * resource bundles and resource strings. However, it is STRONGLY recommended * that application developers make use of the localization features available * within the BlackBerry development platform to ensure a seamless application * experience across a variety of languages and geographies. For more information * on localizing your application, please refer to the BlackBerry Java Development * Environment Development Guide associated with this release. */ package com.rim.samples.device.traveltimedemo; import java.util.Vector; import javax.microedition.location.Coordinates; import javax.microedition.location.Location; import javax.microedition.location.LocationProvider; import net.rim.device.api.i18n.DateFormat; import net.rim.device.api.i18n.SimpleDateFormat; import net.rim.device.api.lbs.maps.model.MapLocation; 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.ChoiceField; import net.rim.device.api.ui.component.DateField; import net.rim.device.api.ui.component.Dialog; import net.rim.device.api.ui.component.LabelField; import net.rim.device.api.ui.component.ObjectChoiceField; import net.rim.device.api.ui.component.TextField; import net.rim.device.api.ui.container.HorizontalFieldManager; import net.rim.device.api.ui.container.MainScreen; import net.rim.device.api.ui.container.VerticalFieldManager; /** * This application consists of a single screen which allows a user to enter a * destination address as a free-form string and then obtain the travel time * between the current location and the specified address. * * The code demonstrates how to use the Travel Time API in conjunction with the * GPS Location API and the Geocoder API. * * Note that to run this application in the simulator, you must tell the * simulator where it is by selecting 'Simulator > GPS Location' and entering a * latitude and longitude. */ public final class TravelTimeDemo extends UiApplication { /** * Entry point for application * * @param args * Command line arguments (not used) */ public static void main(final String[] args) { // Create a new instance of the application and make the currently // running thread the application's event dispatch thread. final TravelTimeDemo theApp = new TravelTimeDemo(); theApp.enterEventDispatcher(); } /** * Creates a new TravelTimeDemo object */ public TravelTimeDemo() { pushScreen(new TravelTimeDemoScreen()); } } /** * Main screen for the Travel Time Demo application */ final class TravelTimeDemoScreen extends MainScreen { private static final int DEPART_NOW = 0; private static final int DEPART_AT = 1; private static final int ARRIVE_AT = 2; private final LabelField _statusField; private final BasicEditField _addressField; private final LabelField _startLabel; private final LabelField _endLabel; private final LabelField _elapsedLabel; private final LabelField _distanceLabel; private final ObjectChoiceField _choiceField; private final DateField _dateField; /** * Creates a new TravelTimeDemoScreen */ public TravelTimeDemoScreen() { setTitle("Travel Time Demo"); // Initialize status field _statusField = new LabelField(""); setStatus(_statusField); // Free form address entry field _addressField = new BasicEditField("Destination: ", "", 500, TextField.NO_NEWLINE); add(_addressField); // Start/end time selection final VerticalFieldManager vfm = new VerticalFieldManager(); _choiceField = new ObjectChoiceField("When:", new Object[] { "Depart Now", "Depart At", "Arrive At" }, 0); _choiceField.setChangeListener(new FieldChangeListener() { /** * @see net.rim.device.api.ui.FieldChangeListener#fieldChanged(Field, * int) */ public void fieldChanged(final Field field, final int context) { if (context == ChoiceField.CONTEXT_CHANGE_OPTION) { final int idx = _choiceField.getSelectedIndex(); if (idx == DEPART_NOW) { _dateField.setEnabled(false); } else { _dateField.setEnabled(true); _dateField.setFocus(); } } } }); vfm.add(_choiceField); final DateFormat dateFormat = DateFormat.getInstance(DateFormat.DATETIME_DEFAULT); _dateField = new DateField("", System.currentTimeMillis(), dateFormat); _dateField.setEnabled(false); vfm.add(_dateField); add(vfm); // Initialize a button for intitiating a travel time query final HorizontalFieldManager hfm = new HorizontalFieldManager(Field.FIELD_HCENTER); final ButtonField travelButton = new ButtonField("Get Travel Time", ButtonField.CONSUME_CLICK | ButtonField.NEVER_DIRTY); hfm.add(travelButton); add(hfm); travelButton.setChangeListener(new FieldChangeListener() { public void fieldChanged(final Field field, final int context) { findTravelTime(); } }); // Add labels to display travel time results _startLabel = new LabelField(); add(_startLabel); _endLabel = new LabelField(); add(_endLabel); _elapsedLabel = new LabelField(); add(_elapsedLabel); _distanceLabel = new LabelField(); add(_distanceLabel); } /** * @see net.rim.device.api.ui.container.MainScreen#onSavePrompt() */ protected boolean onSavePrompt() { // Supress the save dialog return true; } /** * Performs the work of obtaining the starting and ending points and * requesting a travel time estimate. */ private void findTravelTime() { // Ensure that an address has been entered final String address = _addressField.getText(); if (address == null || address.length() == 0) { Dialog.alert("Address field cannot be empty"); return; } // Clear the results fields _startLabel.setText(""); _endLabel.setText(""); _elapsedLabel.setText(""); _distanceLabel.setText(""); // Determine whether an arrival or departure estimate is desired and // read the appropriate time. final int choice = _choiceField.getSelectedIndex(); final long startTime; final long endTime; if (choice == DEPART_NOW) { startTime = TravelTime.START_NOW; endTime = 0; } else if (choice == DEPART_AT) { startTime = _dateField.getDate(); endTime = 0; } else { startTime = 0; endTime = _dateField.getDate(); } // To obtain the starting point, we must obtain the latitude and // longitude corresponding to the specified address. This done using // the geocode() method of the Geocoder API. Since we are not passing // a callback object to this method this will be a blocking method and // cannot be called on the same thread as the event dispatcher (i.e. the // main thread). Similarly the GPS location is obtained using a blocking // method and cannot be called on the event dispatch thread. Therefore, // a separate thread is created to host the geocoding and GPS locating. // Since a separate thread is already being created, the synchronous // Travel Time API method is the most straightforward and appropriate to // use in this case. final Thread travelTimeThread = new Thread() { public void run() { try { // Attempt to geocode the destination address showStatus("Geocoding destination address..."); final GeocodeExchange ex = Geocoder.getInstance().geocode(null, address, null, 0); final Vector results = ex.getResults(); if (results.size() == 0) { throw new Exception("Could not geocode address"); } final MapLocation mapLocation = (MapLocation) results.elementAt(0); final Coordinates endPoint = new Coordinates(mapLocation.getLat(), mapLocation .getLon(), 0); // Obtain the coordinates for the current location showStatus("Finding current location..."); final LocationProvider provider = LocationProvider.getInstance(null); if (provider == null) { throw new IllegalStateException( "no LocationProvider available"); } final Location location = provider.getLocation(-1); final Coordinates startPoint = location.getQualifiedCoordinates(); // Obtain the travel time between the two points showStatus("Obtaining travel time estimate..."); final TravelTimeEstimator estimator = TravelTimeEstimator.getInstance(); TravelTime travelTime; if (endTime > 0) { travelTime = estimator.requestDepartureEstimate(startPoint, endPoint, endTime, null); } else { travelTime = estimator.requestArrivalEstimate(startPoint, endPoint, startTime, null); } showStatus("Done"); showResults(travelTime); } catch (final Exception e) { showStatus(""); // Use invokeLater() so that the dialog will be spawned // on the event thread. Application.getApplication().invokeLater(new Runnable() { public void run() { Dialog.alert(e.getClass().getName() + "\n\n" + e.getMessage()); } }); } } }; travelTimeThread.start(); } /** * Updates the status field * * @param message * Text to display */ private void showStatus(final String message) { // Use invokeLaterAndWait() so that the update occurs on the event // thread Application.getApplication().invokeAndWait(new Runnable() { /** * @see java.lang.Runnable#run() */ public void run() { _statusField.setText(message); } }); } /** * Updates the results fields with results of a travel time query * * @param travelTime * A TravelTime object containing results of a query */ private void showResults(final TravelTime travelTime) { // Use invokeLater() so that the update occurs on the event thread Application.getApplication().invokeLater(new Runnable() { /** * @see java.lang.Runnable#run() */ public void run() { // Convert form the elapsed time in milliseconds to an // hour:minute:seconds format. long value = travelTime.getElapsedTime() / 1000; final long seconds = value % 60; value /= 60; final long minutes = value % 60; final long hours = value / 60; final 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); final DateFormat dateFormatter = new SimpleDateFormat(DateFormat.DATETIME_DEFAULT); String dateStr = dateFormatter.formatLocal(travelTime.getStartTime()); String msg = "Start Time: " + dateStr; _startLabel.setText(msg); dateStr = dateFormatter.formatLocal(travelTime.getEndTime()); msg = "End Time: " + dateStr; _endLabel.setText(msg); msg = "Travel Time (h:m:s): " + buffer.toString(); _elapsedLabel.setText(msg); // Convert the distance from meters to kilometers final double distance = travelTime.getDistance() / 1000.0; msg = "Distance (km): " + Double.toString(distance); _distanceLabel.setText(msg); } }); } }