/**
* ExtendedGPSDiagnosticScreen.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.gpsdemoadvanced;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.location.Location;
import javax.microedition.location.LocationException;
import javax.microedition.location.LocationListener;
import javax.microedition.location.LocationProvider;
import net.rim.blackberry.api.invoke.Invoke;
import net.rim.blackberry.api.invoke.MapsArguments;
import net.rim.device.api.command.Command;
import net.rim.device.api.command.CommandHandler;
import net.rim.device.api.command.ReadOnlyCommandMetadata;
import net.rim.device.api.gps.BlackBerryCriteria;
import net.rim.device.api.gps.BlackBerryLocation;
import net.rim.device.api.gps.BlackBerryLocationProvider;
import net.rim.device.api.gps.GPSInfo;
import net.rim.device.api.gps.GPSSettings;
import net.rim.device.api.gps.LocationInfo;
import net.rim.device.api.i18n.SimpleDateFormat;
import net.rim.device.api.io.LineReader;
import net.rim.device.api.system.DeviceInfo;
import net.rim.device.api.system.EventLogger;
import net.rim.device.api.system.RadioInfo;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BasicEditField;
import net.rim.device.api.ui.component.CheckboxField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.component.ObjectChoiceField;
import net.rim.device.api.ui.component.SeparatorField;
import net.rim.device.api.ui.component.TextField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.util.StringProvider;
/**
* Tests the use of the extended APIs included in the net.rim.device.api.gps
* package.
*
* There are several available modes the user can choose. (m) stands for
* 'multiple fix' and (s) stands for 'single fix'
*
* In Smart Mode the application operates in MS-Based mode but falls back to
* MS-Assisted for a single fix if the LocationProvider is unable to return a
* valid fix in (maxInvalidTime) seconds. The provider then goes back to
* MS-Based again.
*
* For any assisted modes (all those except Stand Alone or Cellsite), additional
* helper data from a PDE server is required.
*/
public class ExtendedGPSDiagnosticScreen extends MainScreen implements
FieldChangeListener {
// Provides a reference to the UIApplication for faster updating
private final UiApplication _uiApp;
// TextField to show the logs
private TextField _log;
// The available modes the user can choose
private ObjectChoiceField _primaryModeField;
// Checkbox to enable geolocation falback
private CheckboxField _enableGeolocationFallbackField;
// Checkbox to enable concurrent geolocation
private CheckboxField _enableConcurrentGeolocationField;
// Check box to indicate whether location should be displayed on a map
private CheckboxField _isMapLocationField;
// Check box to specify whether to set gpsRestartInterval
private CheckboxField _useGPSRestartIntervalField;
// Check box to specify whether detailed satellite info is required
private CheckboxField _isSatelliteInfoRequiredField;
// Indicates if the device is on Verizon. If so, app credentials will be set
// instead of PDE IP and Port.
private CheckboxField _isVerizonField;
// Field to choose a failover mode
private ObjectChoiceField _failOverModeField;
// Field to choose a mode to be used after the first fix
private ObjectChoiceField _subsequentModeField;
// Field to specify the zoom level used in the BlackBerry Maps application
private BasicEditField _zoomLevelField;
// Field to enter the preferred response time
private BasicEditField _preferredResponseTimeField;
// Field to enter the interval parameter for a LocationListener
private BasicEditField _frequencyField;
// Field to enter the timeout parameter for a LocationListener
private BasicEditField _timeoutField;
// Field to enter the maximum age of the returned location in seconds
private BasicEditField _maxAgeField;
// Field to enter the maximum number of GPS retries (using the selected
// mode)
// before a failover occurs.
private BasicEditField _failOverRetriesField;
// Field to enter the maximum wait time (in seconds) to get a fix before a
// failover occurs
private BasicEditField _failoverTimeoutField;
// Field to enter the time (in seconds) the JSR179 extension will wait
// before
// automatically restarting GPS.
private BasicEditField _gpsRestartIntervalField;
// Field to enter the maximum number of GPS restarts
private BasicEditField _gpsRestartRetriesField;
// Field to enter the PDE IP
private BasicEditField _pdeIPField;
// Field to enter the PDE port
private BasicEditField _pdePortField;
// Displays the supported location data sources for the device
private BasicEditField _supportedSourcesField;
// Displays the available location data sources of the device
private BasicEditField _availableSourcesField;
// Displays the GPS mode used for the current location
private BasicEditField _currentModeField;
// Displays the number of satellites used to compute the current fix
private BasicEditField _currentSatellitesCountField;
// Displays the location information for the current fix
private EditField _currentLocationField;
// Displays the average satellite signal quality of the current fix
private EditField _currentAverageSatelliteSignalField;
// Displays the DataSource used to get the current fix
private EditField _currentDataSourceField;
// Displays an error for the current GPS fix
private EditField _currentErrorField;
// Displays the status of the current fix
private EditField _currentStatusField;
// Displays the total number of updates that have occurred
private EditField _numberUpdatesField;
// Displays the total number of MS-Assisted updates that have occurred
private EditField _numberAssistedUpdatesField;
// Displays the total number of MS-Based updates that have occurred
private EditField _numberUnassistedUpdatesField;
// Displays the total number of valid updates that have occurred
private EditField _numberValidUpdatesField;
// Displays the total number of invalid updates that have occurred
private EditField _numberInvalidUpdatesField;
// This Thread performs all location related work
private LocationThread _locThread;
// Flag indicating an immediate reset is required due to
// TEMPORARILY_UNAVAILABLE event
private boolean _resetNow;
// A menu item for stopping a running test
private final MenuItem _stopTestItem;
private boolean _PDESet;
/**
* Creates a new ExtendedGPSDiagnosticScreen object
*/
public ExtendedGPSDiagnosticScreen() {
// Initialize the reference to the UiApplication
_uiApp = UiApplication.getUiApplication();
// Initialize UI components
setTitle("Extended GPS Diagnostic Test");
initFields();
_isVerizonField.setChangeListener(this);
// A MenuItem to start the diagnostic test
final MenuItem startTestItem =
new MenuItem(new StringProvider("Start Test"), 0x300010, 0);
;
startTestItem.setCommand(new Command(new CommandHandler() {
/**
* @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(final ReadOnlyCommandMetadata metadata,
final Object context) {
// Format the UI for output
showOutputFields();
// Begin test
if (_locThread != null) {
if (!_locThread.isStopped()) {
_locThread.stop();
}
}
_log.setText("");
log("Extended GPS API test starting");
log("Device: " + DeviceInfo.getDeviceName());
log("Device Software: " + DeviceInfo.getSoftwareVersion());
log("Carrier: " + RadioInfo.getCurrentNetworkName());
_locThread = new LocationThread();
_locThread.start();
}
}));
addMenuItem(startTestItem);
_stopTestItem =
new MenuItem(new StringProvider("Stop Test"), 0x300020, 1);
_stopTestItem.setCommand(new Command(new CommandHandler() {
/**
* @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(final ReadOnlyCommandMetadata metadata,
final Object context) {
// Stop the thread
log("Stopping test");
_locThread.stop();
_locThread = null;
}
}));
addMenuItem(_stopTestItem);
// A MenuItem to display the help dialog
final MenuItem helpItem =
new MenuItem(new StringProvider("Help"), 0x300030, 2);
helpItem.setCommand(new Command(new CommandHandler() {
/**
* @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(final ReadOnlyCommandMetadata metadata,
final Object context) {
// Display a pop-up dialog with instructions for using this
// application
displayHelp();
}
}));
addMenuItem(helpItem);
showInputFields();
}
/**
* Initializes the UI fields
*/
private void initFields() {
_log = new TextField();
_log.setLabel("Log: ");
_primaryModeField =
new ObjectChoiceField("Mode: ", new String[] {
"Stand Alone(s)", "Stand Alone(m)", "Data Optimal(m)",
"Speed Optimal(m)", "MS-Based(m)",
"Accuracy Optimal(s)", "PDE Calculate(s)",
"Cellsite(s)", "Cellsite(m)", "Default(s)",
"Default(m)", "Optimal Geolocation(s)",
"Optimal Geolocation(m)", "Cell Geolocation(s)",
"Cell Geolocation(m)", "WLAN Geolocation(s)",
"WLAN Geolocation(m)" }, 1);
_enableGeolocationFallbackField =
new CheckboxField("Enable Geolocation Fallback", false);
_enableConcurrentGeolocationField =
new CheckboxField("Enable Concurrent Geolocation", false);
_isMapLocationField = new CheckboxField("Map Location", false);
_useGPSRestartIntervalField =
new CheckboxField("GPS Restart Interval?", false);
_isSatelliteInfoRequiredField =
new CheckboxField("Satellite information required?", false);
_isVerizonField = new CheckboxField("Verizon?", false);
_failOverModeField =
new ObjectChoiceField("Failover Mode: ",
new String[] { "Stand Alone", "Data Optimal",
"Speed Optimal", "MS-Based",
"Accuracy Optimal", "PDE Calculate", "None" },
6);
_subsequentModeField =
new ObjectChoiceField("Subsequent Mode: ",
new String[] { "Stand Alone", "Data Optimal",
"Speed Optimal", "MS-Based",
"Accuracy Optimal", "PDE Calculate", "None" },
6);
_zoomLevelField = new BasicEditField("Zoom: ", "1");
_preferredResponseTimeField =
new BasicEditField("Pref'd Response Time (sec): ", "16", 6,
BasicEditField.FILTER_INTEGER);
_frequencyField =
new BasicEditField("Fix Frequency (sec): ", "5", 5,
BasicEditField.FILTER_INTEGER);
_timeoutField =
new BasicEditField("Timeout (sec): ", "-1", 5,
BasicEditField.FILTER_INTEGER);
_maxAgeField =
new BasicEditField("MaxAge (sec): ", "-1", 5,
BasicEditField.FILTER_INTEGER);
_failOverRetriesField =
new BasicEditField("Max Retries [0-3]: ", "0", 1,
BasicEditField.FILTER_INTEGER);
_failoverTimeoutField =
new BasicEditField("Failover Timeout [30-300]: ", "30", 3,
BasicEditField.FILTER_INTEGER);
_gpsRestartIntervalField =
new BasicEditField("Restart Interval [2-900]: ", "100", 3,
BasicEditField.FILTER_INTEGER);
_gpsRestartRetriesField =
new BasicEditField("Restart Retries [1-3]: ", "3", 1,
BasicEditField.FILTER_INTEGER);
_pdeIPField = new BasicEditField("PDE IP: ", "");
_pdePortField = new BasicEditField("PDE Port: ", "");
_supportedSourcesField = new BasicEditField("Supported Sources: ", "-");
_availableSourcesField = new BasicEditField("Available Sources: ", "-");
_currentModeField = new BasicEditField("Current Mode: ", "-");
_currentSatellitesCountField = new BasicEditField("Satellites: ", "-");
_currentLocationField = new EditField("Location: ", "-");
_currentAverageSatelliteSignalField =
new EditField("Satellite Signal: ", "-");
_currentDataSourceField = new EditField("Data Source: ", "-");
_currentErrorField = new EditField("Error: ", "-");
_currentStatusField = new EditField("Status: ", "-");
_numberUpdatesField = new EditField("Total Updates: ", "0");
_numberAssistedUpdatesField = new EditField("Assisted: ", "0");
_numberUnassistedUpdatesField = new EditField("Unassisted: ", "0");
_numberValidUpdatesField = new EditField("Valid Updates: ", "0");
_numberInvalidUpdatesField = new EditField("Invalid Updates: ", "0");
}
/**
* Empties the screen and adds the input fields
*/
private void showInputFields() {
// Remove existing UI components
deleteAll();
// Add all input UI components
add(_primaryModeField);
add(new SeparatorField());
add(_enableGeolocationFallbackField);
add(new SeparatorField());
add(_enableConcurrentGeolocationField);
add(new SeparatorField());
add(_isVerizonField);
add(_pdeIPField);
add(_pdePortField);
add(new SeparatorField());
add(_isMapLocationField);
add(_zoomLevelField);
add(new SeparatorField());
add(_preferredResponseTimeField);
add(new SeparatorField());
add(_frequencyField);
add(_timeoutField);
add(_maxAgeField);
add(new SeparatorField());
add(_failOverModeField);
add(_failOverRetriesField);
add(_failoverTimeoutField);
add(new SeparatorField());
add(_useGPSRestartIntervalField);
add(_gpsRestartIntervalField);
add(_gpsRestartRetriesField);
add(new SeparatorField());
add(_subsequentModeField);
add(new SeparatorField());
add(_isSatelliteInfoRequiredField);
add(new SeparatorField());
}
/**
* Empties the screen and adds the output fields
*/
private void showOutputFields() {
// Remove existing UI components
deleteAll();
// Add all output UI components
add(_supportedSourcesField);
add(new SeparatorField());
add(_availableSourcesField);
add(new SeparatorField());
add(new SeparatorField());
add(_currentModeField);
add(new SeparatorField());
add(_currentSatellitesCountField);
add(new SeparatorField());
add(_currentLocationField);
add(new SeparatorField());
add(_currentAverageSatelliteSignalField);
add(new SeparatorField());
add(_currentDataSourceField);
add(new SeparatorField());
add(_currentErrorField);
add(new SeparatorField());
add(_currentStatusField);
add(new SeparatorField());
add(new SeparatorField());
add(_numberUpdatesField);
add(new SeparatorField());
add(_numberAssistedUpdatesField);
add(new SeparatorField());
add(_numberUnassistedUpdatesField);
add(new SeparatorField());
add(_numberValidUpdatesField);
add(new SeparatorField());
add(_numberInvalidUpdatesField);
add(new SeparatorField());
add(new SeparatorField());
add(_log);
}
/**
* Displays a message in the log EditField as well as in the device event
* log
*
* @param message
* The text to be logged
*/
private void log(final String message) {
if (message != null) {
final String newMsg =
formatDate(System.currentTimeMillis()) + message + "\n";
// Add event to device log
EventLogger.logEvent(0x9876543212345L, newMsg.getBytes(),
EventLogger.ALWAYS_LOG);
_uiApp.invokeLater(new Runnable() {
/**
* @see java.lang.Runnable#run()
*/
public void run() {
// If log too long, reset log
if (_log.getText().length() > 1500) {
_log.setText("");
}
// Output message to screen
_log.setText(_log.getText() + newMsg);
}
});
}
}
/**
* Returns a String representation of a date provided in long format
*
* @param date
* Date in long format
* @return String representation of <code>date</code>
*/
private String formatDate(final long date) {
final SimpleDateFormat sdf =
new SimpleDateFormat(SimpleDateFormat.TIME_LONG);
final Date d = new Date(date);
final Calendar cal = Calendar.getInstance();
cal.setTime(d);
final StringBuffer buff = new StringBuffer();
buff.append('[');
buff.append(cal.get(Calendar.DAY_OF_MONTH));
buff.append('-');
buff.append(sdf.format(cal, new StringBuffer(), null).toString());
buff.append("] ");
return buff.toString();
}
/**
* Resets the fix-related UI items to their initial value
*/
void resetDataFields() {
_uiApp.invokeLater(new Runnable() {
/**
* @see java.lang.Runnable#run()
*/
public void run() {
// Clear all fields and set to default values
_currentModeField.setText("-");
_currentSatellitesCountField.setText("-");
_currentLocationField.setText("-");
_currentAverageSatelliteSignalField.setText("-");
_currentDataSourceField.setText("-");
_currentErrorField.setText("-");
_currentStatusField.setText("-");
_numberUpdatesField.setText("0");
_numberAssistedUpdatesField.setText("0");
_numberUnassistedUpdatesField.setText("0");
_numberValidUpdatesField.setText("0");
_numberInvalidUpdatesField.setText("0");
}
});
}
/**
* @see net.rim.device.api.ui.Screen#onClose()
*/
public boolean onClose() {
log("Closing Application");
if (_locThread != null) {
_locThread.stop();
_locThread = null;
}
return super.onClose();
}
/**
* @see net.rim.device.api.ui.Screen#onSavePrompt()
*/
public boolean onSavePrompt() {
// Suppress the save dialog
return true;
}
/**
* @see net.rim.device.api.ui.container.MainScreen#makeMenu(Menu, int)
*/
protected void makeMenu(final Menu menu, final int instance) {
super.makeMenu(menu, instance);
if (_locThread != null) {
menu.setDefault(_stopTestItem);
}
}
/**
* @see net.rim.device.api.ui.FieldChangeListener#fieldChanged(Field, int)
*/
public void fieldChanged(final Field field, final int context) {
if (field == _isVerizonField) {
if (_isVerizonField.getChecked()) {
_pdeIPField.setLabel("Client ID: ");
_pdePortField.setLabel("Password: ");
} else {
_pdeIPField.setLabel("PDE IP: ");
_pdePortField.setLabel("PDE Port: ");
}
}
}
/**
* Displays the help dialog
*/
private void displayHelp() {
final InputStream stream =
getClass().getResourceAsStream("/resource/help_extended.txt");
final LineReader lineReader = new LineReader(stream);
final StringBuffer help = new StringBuffer();
for (;;) {
try {
help.append(new String(lineReader.readLine()));
help.append('\n');
} catch (final EOFException eof) {
// We've reached the end of the file
break;
} catch (final IOException ioe) {
Dialog.alert("LineReader#readLine() threw " + ioe.toString());
return;
}
}
Dialog.inform(help.toString());
}
/**
* All the location related tasks are performed in this Thread
*/
private class LocationThread extends Thread {
/**
* If true, the application will use a LocationListener to continually
* provide updates with regard to location. If false, a single call to
* LocationProvider.getLocation() will be made.
*/
private boolean _isMultipleFixes = true;
// Determines the mode of the LocationProvider
private BlackBerryCriteria _bbCriteria;
// Counter variables for valid, invalid, assisted, unassisted and total
// updates
private int _totalUpdates, _validUpdates, _inValidUpdates,
_assistedUpdates, _unassistedUpdates;
// Reference to the BlackBerryLocationProvider
private BlackBerryLocationProvider _bbProvider;
// Location object that holds the current fix
private BlackBerryLocation _bbLocation;
// Holds integer values representing supported and available location
// data sources
private int _supportedSourcesMask, _availableSourcesMask;
// Indicates whether the thread has been stopped
private boolean _isStopped;
/**
* @see java.lang.Thread#run()
*/
public void run() {
// Clear the current data
resetDataFields();
if (!LocationInfo.isLocationOn()) {
LocationInfo.setLocationOn();
}
_supportedSourcesMask = LocationInfo.getSupportedLocationSources();
_availableSourcesMask = LocationInfo.getAvailableLocationSources();
_uiApp.invokeLater(new Runnable() {
/**
* @see java.lang.Runnable#run()
*/
public void run() {
_supportedSourcesField
.setText(getDataSourceString(_supportedSourcesMask));
_availableSourcesField
.setText(getDataSourceString(_availableSourcesMask));
}
});
// Setup and connect to the provider
try {
setupCriteria();
} catch (final net.rim.device.api.system.UnsupportedOperationException uoe) {
log(_primaryModeField.getChoice(_primaryModeField
.getSelectedIndex())
+ " is not supported on this device\nTest stopped");
return;
}
log("Criteria initialized");
if (!_PDESet) {
setupPDE();
}
log("Starting Updates: " + formatDate(System.currentTimeMillis()));
setupProvider();
}
/*
* Sets up the PDE server
*/
private void setupPDE() {
final String pdeIPText = _pdeIPField.getText();
final String pdePortText = _pdePortField.getText();
if (pdeIPText.length() > 0) {
if (!_isVerizonField.getChecked()) {
log("Using PDE: " + pdeIPText + ":" + pdePortText);
final boolean setPDESuccess =
GPSSettings.setPDEInfo(pdeIPText, Integer
.parseInt(pdePortText));
if (setPDESuccess) {
_PDESet = true;
log("setPDEInfo() successful");
}
} else {
// Set Verizon specific settings
log("Using VZ Credentials: " + ";" + pdeIPText + ";"
+ pdePortText);
GPSSettings.setPDEInfo(";" + pdeIPText + ";" + pdePortText,
0);
// Verizon Verizon PDE server sessions time out after
// 12 hours. Set up a timer to reset the connection
// at ~12 hour intervals.
final Timer timer = new Timer();
final TimerTask task = new TimerTask() {
/**
* @see java.util.TimerTask#run()
*/
public void run() {
clearVerizonCredential();
setupPDE();
resetProvider();
setupProvider();
}
};
// Set period to just under 12 hours
final long period = 1000 * 60 * 60 * 12 - 60000;
// Set date to just under 12 hours from now
long date = new Date().getTime();
date = date + period;
timer.scheduleAtFixedRate(task, period, date);
_PDESet = true;
}
}
}
/**
* Initializes criteria according to the mode selected by the user. The
* following algorithm is used: If costAllowed = FALSE mode is Stand
* Alone Otherwise, if costAllowed=TRUE, -if horizontalAccuracy = 0,
* mode is Data Optimal -if horizontalAccuracy > 0, -if multiple fixes
* requested, -if Telus, mode is MS-based -otherwise, -if powerUsage =
* HIGH, mode is Speed Optimal; -if powerUsage != HIGH, mode is MS-based
* -else if single fix requested, -if powerUsage = HIGH, mode is
* Accuracy Optimal -if powerUsage != HIGH, mode is PDE Calculate -if
* powerUsage = LOW mode is Cellsite
*/
private void setupCriteria() {
_bbCriteria = new BlackBerryCriteria();
_bbCriteria.setPreferredResponseTime(Integer
.parseInt(_preferredResponseTimeField.getText()));
if (_enableConcurrentGeolocationField.getChecked()) {
_bbCriteria
.enableGeolocationWithGPS(BlackBerryCriteria.FASTEST_FIX_PREFERRED);
} else if (_enableGeolocationFallbackField.getChecked()) {
_bbCriteria.enableGeolocationWithGPS();
}
switch (_primaryModeField.getSelectedIndex()) {
case 0: // Stand Alone(s)
_isMultipleFixes = false;
_bbCriteria.setMode(GPSInfo.GPS_MODE_AUTONOMOUS);
log("Primary mode set to Stand Alone");
break;
case 1: // Stand Alone(m)
_isMultipleFixes = true;
_bbCriteria.setMode(GPSInfo.GPS_MODE_AUTONOMOUS);
log("Primary mode set to Stand Alone");
break;
case 2: // Data Optimal(m)
_isMultipleFixes = true;
_bbCriteria.setMode(GPSInfo.GPS_MODE_CDMA_DATA_OPTIMAL);
log("Primary mode set to Data Optimal");
break;
case 3: // Speed Optimal(m)
_isMultipleFixes = true;
_bbCriteria.setMode(GPSInfo.GPS_MODE_CDMA_SPEED_OPTIMAL);
log("Primary mode set to Speed Optimal");
break;
case 4: // MS-Based(m)
_isMultipleFixes = true;
_bbCriteria.setMode(GPSInfo.GPS_MODE_CDMA_MS_BASED);
log("Primary mode set to MS-Based");
break;
case 5: // Accuracy Optimal(s)
_isMultipleFixes = false;
_bbCriteria.setMode(GPSInfo.GPS_MODE_CDMA_ACCURACY_OPTIMAL);
log("Primary mode set to Accuracy Optimal");
break;
case 6: // PDE Calculate(s)
_isMultipleFixes = false;
_bbCriteria.setMode(GPSInfo.GPS_MODE_CDMA_MS_ASSIST);
log("Primary mode set to PDE Calculate");
break;
case 7: // Cellsite(s)
_isMultipleFixes = false;
_bbCriteria.setMode(GPSInfo.GPS_MODE_CELLSITE);
log("Primary mode set to Cellsite(s)");
break;
case 8: // Cellsite(m)
_isMultipleFixes = true;
_bbCriteria.setMode(GPSInfo.GPS_MODE_CELLSITE);
log("Primary mode set to Cellsite(m)");
break;
case 9: // Default(s)
_isMultipleFixes = false;
log("Primary mode set to Default(m)");
break;
case 10: // Default(m)
_isMultipleFixes = true;
log("Primary mode set to Default(m)");
break;
case 11: // Optimal Geolocation(s)
_isMultipleFixes = false;
_bbCriteria =
new BlackBerryCriteria(LocationInfo.GEOLOCATION_MODE);
break;
case 12: // Optimal Geolocation(m)
_isMultipleFixes = true;
_bbCriteria =
new BlackBerryCriteria(LocationInfo.GEOLOCATION_MODE);
break;
case 13: // Cell Geolocation(s)
_isMultipleFixes = false;
_bbCriteria =
new BlackBerryCriteria(
LocationInfo.GEOLOCATION_MODE_CELL);
break;
case 14: // Cell Geolocation(m)
_isMultipleFixes = true;
_bbCriteria =
new BlackBerryCriteria(
LocationInfo.GEOLOCATION_MODE_CELL);
break;
case 15: // WLAN Geolocation(s)
_isMultipleFixes = false;
_bbCriteria =
new BlackBerryCriteria(
LocationInfo.GEOLOCATION_MODE_WLAN);
break;
case 16: // WLAN Geolocation(m)
_isMultipleFixes = true;
_bbCriteria =
new BlackBerryCriteria(
LocationInfo.GEOLOCATION_MODE_WLAN);
break;
}
if (_failOverModeField.getSelectedIndex() < 6) {
final int foRetries =
Integer.parseInt(_failOverRetriesField.getText());
final int foTimeout =
Integer.parseInt(_failoverTimeoutField.getText());
switch (_failOverModeField.getSelectedIndex()) {
case 0: // Stand Alone
_bbCriteria.setFailoverMode(GPSInfo.GPS_MODE_AUTONOMOUS,
foRetries, foTimeout);
log("failOverMode set to Stand Alone");
break;
case 1: // Data Optimal
_bbCriteria.setFailoverMode(
GPSInfo.GPS_MODE_CDMA_DATA_OPTIMAL, foRetries,
foTimeout);
log("failOverMode set to Data Optimal");
break;
case 2: // Speed Optimal
_bbCriteria.setFailoverMode(
GPSInfo.GPS_MODE_CDMA_SPEED_OPTIMAL, foRetries,
foTimeout);
log("failOverMode set to Speed Optimal");
break;
case 3: // MS-Based
_bbCriteria.setFailoverMode(GPSInfo.GPS_MODE_CDMA_MS_BASED,
foRetries, foTimeout);
log("failOverMode set to MS-Based");
break;
case 4: // Accuracy Optimal
_bbCriteria.setFailoverMode(
GPSInfo.GPS_MODE_CDMA_ACCURACY_OPTIMAL, foRetries,
foTimeout);
log("failOverMode set to Accuracy Optimal");
break;
case 5: // PDE Calculate
_bbCriteria.setFailoverMode(
GPSInfo.GPS_MODE_CDMA_MS_ASSIST, foRetries,
foTimeout);
log("failOverMode set to PDE Calculate");
break;
}
}
// Apply user settings
if (_useGPSRestartIntervalField.getChecked()) {
final int interval =
Integer.parseInt(_gpsRestartIntervalField.getText());
final int maximumRetry =
Integer.parseInt(_gpsRestartRetriesField.getText());
_bbCriteria.setGPSRestartInterval(interval, maximumRetry);
}
if (_isSatelliteInfoRequiredField.getChecked()) {
_bbCriteria.setSatelliteInfoRequired(true, true);
}
if (_subsequentModeField.getSelectedIndex() < 6) {
switch (_subsequentModeField.getSelectedIndex()) {
case 0: // Stand Alone
_bbCriteria.setSubsequentMode(GPSInfo.GPS_MODE_AUTONOMOUS);
log("subsequentMode set to Stand Alone");
break;
case 1: // Data Optimal
_bbCriteria
.setSubsequentMode(GPSInfo.GPS_MODE_CDMA_DATA_OPTIMAL);
log("subsequentMode set to Data Optimal");
break;
case 2: // Speed Optimal
_bbCriteria
.setSubsequentMode(GPSInfo.GPS_MODE_CDMA_SPEED_OPTIMAL);
log("subsequentMode set to Speed Optimal");
break;
case 3: // MS-Based
_bbCriteria
.setSubsequentMode(GPSInfo.GPS_MODE_CDMA_MS_BASED);
log("subsequentMode set to MS-Based");
break;
case 4: // Accuracy Optimal
_bbCriteria
.setSubsequentMode(GPSInfo.GPS_MODE_CDMA_ACCURACY_OPTIMAL);
log("subsequentMode set to Accuracy Optimal");
break;
case 5: // PDE Calculate
_bbCriteria
.setSubsequentMode(GPSInfo.GPS_MODE_CDMA_MS_ASSIST);
log("subsequentMode set to PDE Calculate");
break;
}
}
}
/**
* Reset logic for LocationProvider
*/
private void resetProvider() {
log("Resetting LocationProvider");
_bbProvider.setLocationListener(null, 0, 0, 0);
_bbProvider.reset();
_bbProvider = null;
}
/**
* Reset credential logic for Verizon. The Verizon PDE session needs to
* be refreshed every 12 hours (contact Verizon for more information).
*/
private void clearVerizonCredential() {
final Thread resetThread = new Thread() {
/**
* @see java.lang.Thread#run()
*/
public void run() {
final BlackBerryCriteria oldBBCriteria = _bbCriteria;
_bbCriteria.setMode(GPSInfo.GPS_MODE_CDMA_MS_ASSIST);
LocationProvider tempProvider = null;
try {
tempProvider =
LocationProvider.getInstance(_bbCriteria);
} catch (final LocationException e) {
log(e.toString());
}
if (tempProvider != null) {
log("Clearing VZ credentials. Please wait...");
try {
Thread.sleep(2000);
} catch (final InterruptedException e) {
log(e.toString());
}
GPSSettings.setPDEInfo("127.0.0.1", 0);
try {
Thread.sleep(2000);
} catch (final InterruptedException e) {
log(e.toString());
}
try {
tempProvider.getLocation(1);
} catch (final Exception e) {
log(e.toString());
}
try {
Thread.sleep(15000);
} catch (final InterruptedException e) {
log(e.toString());
}
tempProvider = null;
log("Old Verizon session cleared");
}
_bbCriteria = oldBBCriteria;
}
};
resetThread.start();
try {
resetThread.join();
} catch (final InterruptedException e) {
log(e.toString());
}
}
/**
* This method initializes the LocationProvider and sets a
* LocationListener if <code>isMultipleFixes</code> is TRUE. Otherwise
* it simply calls singleFixLocationUpdate() which calls
* LocationProvider.getLocation() once to get a single fix.
*/
private void setupProvider() {
try {
// Disable resetNow
if (_resetNow) {
_resetNow = false;
}
log("setupProvider()");
try {
// Sleep to ensure _bbProvider and _bbCriteria have enough
// time to be instantiated
Thread.sleep(5000);
} catch (final InterruptedException ie) {
log(ie.toString());
}
_bbProvider =
(BlackBerryLocationProvider) LocationProvider
.getInstance(_bbCriteria);
log("LocationProvider initialized");
if (_bbProvider != null) {
if (_isMultipleFixes) {
final int frequency =
Integer.parseInt(_frequencyField.getText());
final int timeout =
Integer.parseInt(_timeoutField.getText());
final int maxage =
Integer.parseInt(_maxAgeField.getText());
_bbProvider.setLocationListener(new LocListener(),
frequency, timeout, maxage);
log("LocationListener started");
} else {
log("Initiating single shot GPS fix");
singleFixLocationUpdate();
}
} else {
log("Provider unavailable for Criteria");
}
} catch (final LocationException le) {
log(le.toString());
}
}
/**
* Gets a single fix by calling LocationProvider.getLocation(). Updates
* the UI with the fix information. In case of a valid fix it maps the
* fix by invoking the Maps application.
*/
private void singleFixLocationUpdate() {
try {
_bbLocation =
(BlackBerryLocation) _bbProvider.getLocation(Integer
.parseInt(_timeoutField.getText()));
} catch (final InterruptedException ie) {
log("InterruptedException thrown by getLocation(): "
+ ie.getMessage());
} catch (final LocationException le) {
log("LocationException thrown by getLocation(): "
+ le.getMessage());
}
if (_bbLocation != null) {
logLocation(_bbLocation);
} else {
log("Location is null");
}
}
/**
* Displays and logs information about the given location object
*
* @param location
* location object to display and log
*/
private void logLocation(final BlackBerryLocation location) {
_uiApp.invokeLater(new Runnable() {
/**
* @see java.lang.Runnable#run()
*/
public void run() {
_numberUpdatesField.setText(Integer
.toString(++_totalUpdates));
}
});
if (location.isValid()) {
_uiApp.invokeLater(new Runnable() {
/**
* @see java.lang.Runnable#run()
*/
public void run() {
// Update UI fields to reflect new location
_currentModeField.setText(getGPSModeString(location
.getGPSMode())
+ getLocMethodString(location
.getLocationMethod()));
final StringBuffer buff =
new StringBuffer(location
.getQualifiedCoordinates()
.getLatitude()
+ " ");
buff.append(location.getQualifiedCoordinates()
.getLongitude());
buff.append(' ');
buff.append(location.getQualifiedCoordinates()
.getAltitude());
buff.append(' ');
_currentLocationField.setText(buff.toString());
_currentSatellitesCountField.setText(Integer
.toString(location.getSatelliteCount()));
_currentAverageSatelliteSignalField.setText(Integer
.toString(location
.getAverageSatelliteSignalQuality()));
_currentDataSourceField
.setText(getDataSourceString(location
.getDataSource()));
_currentErrorField.setText(getErrorMessage(location
.getError()));
_currentStatusField.setText(getStatusString(location
.getStatus()));
_numberValidUpdatesField.setText(Integer
.toString(++_validUpdates));
if (location.getGPSMode() != GPSInfo.GPS_MODE_AUTONOMOUS) {
_numberAssistedUpdatesField.setText(Integer
.toString(++_assistedUpdates));
} else {
_numberUnassistedUpdatesField.setText(Integer
.toString(++_unassistedUpdates));
}
}
});
StringBuffer buff = new StringBuffer();
buff.append(location.getQualifiedCoordinates().getLatitude());
buff.append(", ");
buff.append(location.getQualifiedCoordinates().getLongitude());
buff.append(' ');
buff.append(location.getQualifiedCoordinates().getAltitude());
if (_isMultipleFixes) {
_currentLocationField.setText("Valid single fix: "
+ buff.toString());
} else {
log("Valid multiple fix: " + buff.toString());
}
buff = new StringBuffer("\tGPS Mode: ");
buff.append(getGPSModeString(location.getGPSMode()));
buff.append(getLocMethodString(location.getLocationMethod()));
buff.append(", Satellite Count: ");
buff.append(Integer.toString(location.getSatelliteCount()));
buff.append(", Signal Strength: ");
buff.append(Integer.toString(location
.getAverageSatelliteSignalQuality()));
log(buff.toString());
buff = new StringBuffer("\tData Source: ");
buff.append(getDataSourceString(location.getDataSource()));
buff.append(", GPS Error: ");
buff.append(getErrorMessage(location.getError()));
buff.append(", Status: ");
buff.append(getStatusString(location.getStatus()));
log(buff.toString());
if (_isMapLocationField.getChecked()) {
// Launch the Maps application to display the given location
displayLocationOnMap(location);
}
} else {
if (_isMultipleFixes && _resetNow) {
resetProvider();
setupProvider();
return;
}
_uiApp.invokeLater(new Runnable() {
/**
* @see java.lang.Runnable#run()
*/
public void run() {
// Update the UI to reflect invalid fix
_currentModeField.setText(getGPSModeString(location
.getGPSMode()));
_currentLocationField.setText("*UNKNOWN*");
_currentSatellitesCountField.setText(Integer
.toString(location.getSatelliteCount()));
_currentAverageSatelliteSignalField.setText(Integer
.toString(location
.getAverageSatelliteSignalQuality()));
_currentDataSourceField
.setText(getDataSourceString(location
.getDataSource()));
_currentErrorField.setText(getErrorMessage(location
.getError()));
_currentStatusField.setText(getStatusString(location
.getStatus()));
_numberInvalidUpdatesField.setText(Integer
.toString(++_inValidUpdates));
}
});
if (_isMultipleFixes) {
log("Invalid multiple fix");
} else {
log("Invalid single fix");
}
StringBuffer buff = new StringBuffer("\tGPS Mode: ");
buff.append(getGPSModeString(location.getGPSMode()));
buff.append(getLocMethodString(location.getLocationMethod()));
buff.append(", Satellite Count: ");
buff.append(Integer.toString(location.getSatelliteCount()));
buff.append(", Signal Strength: ");
buff.append(Integer.toString(location
.getAverageSatelliteSignalQuality()));
log(buff.toString());
buff = new StringBuffer("\tData Source: ");
buff.append(getDataSourceString(location.getDataSource()));
buff.append(", GPS Error: ");
buff.append(getErrorMessage(location.getError()));
buff.append(", Status: ");
buff.append(getStatusString(location.getStatus()));
log(buff.toString());
}
}
/**
* Returns a String representation of a given fix status code
*
* @param status
* Given status code
* @return String representation of status code
*/
private String getStatusString(final int status) {
final StringBuffer statusString = new StringBuffer();
switch (status) {
case BlackBerryLocation.GPS_ERROR:
statusString.append("*ERROR");
break;
case BlackBerryLocation.GPS_FIX_COMPLETE:
statusString.append("*FIX_COMPLETE");
break;
case BlackBerryLocation.GPS_FIX_PARTIAL:
statusString.append("*FIX_PARTIAL");
break;
case BlackBerryLocation.GPS_FIX_UNAVAILABLE:
statusString.append("*FIX_UNAVAILABLE");
break;
case BlackBerryLocation.FAILOVER_MODE_ON:
statusString.append("*FAILOVER_MODE_ON");
break;
case BlackBerryLocation.SUBSEQUENT_MODE_ON:
statusString.append("*SUBSEQUENT_MODE_ON");
break;
}
statusString.append("*");
return statusString.toString();
}
/**
* Returns a String representation for a given data source
*
* @param source
* Integer representation of data source
* @return String representation of data source
*/
private String getDataSourceString(final int source) {
final StringBuffer result = new StringBuffer("*");
switch (source) {
case GPSInfo.GPS_DEVICE_BLUETOOTH:
result.append("GPS_DEVICE_BLUETOOTH");
break;
case GPSInfo.GPS_DEVICE_INTERNAL:
result.append("GPS_DEVICE_INTERNAL");
break;
case LocationInfo.LOCATION_SOURCE_GEOLOCATION:
result.append("LOCATION_SOURCE_GEOLOCATION");
break;
case LocationInfo.LOCATION_SOURCE_GEOLOCATION_CELL:
result.append("LOCATION_SOURCE_GEOLOCATION_CELL");
break;
case LocationInfo.LOCATION_SOURCE_GEOLOCATION_WLAN:
result.append("LOCATION_SOURCE_GEOLOCATION_WLAN");
break;
default:
return "*UNKNOWN*";
}
result.append("*");
return result.toString();
}
/**
* Returns a String representation of the location method being used
*
* @param method
* The location method for which to retrieve a string
* @return location Location method String
*/
private String getLocMethodString(final int method) {
final StringBuffer buf = new StringBuffer();
if ((method & Location.MTA_ASSISTED) != 0) {
buf.append("*MTA_ASSISTED");
}
if ((method & Location.MTA_UNASSISTED) != 0) {
buf.append("*MTA_UNASSISTED");
}
if ((method & Location.MTE_ANGLEOFARRIVAL) != 0) {
buf.append("*MTE_ANGLEOFARRIVAL");
}
if ((method & Location.MTE_CELLID) != 0) {
buf.append("*MTE_CELLID");
}
if ((method & Location.MTE_SATELLITE) != 0) {
buf.append("*MTE_SATELLITE");
}
if ((method & Location.MTE_SHORTRANGE) != 0) {
buf.append("*MTE_SHORTRANGE");
}
if ((method & Location.MTE_TIMEDIFFERENCE) != 0) {
buf.append("*MTE_TIMEDIFFERENCE");
}
if ((method & Location.MTE_TIMEOFARRIVAL) != 0) {
buf.append("*MTE_TIMEOFARRIVAL");
}
if ((method & Location.MTY_NETWORKBASED) != 0) {
buf.append("*MTY_NETWORKBASED");
}
if ((method & Location.MTY_TERMINALBASED) != 0) {
buf.append("*MTY_TERMINALBASED");
}
buf.append("*");
if (buf.length() < 2) {
return "";
} else {
return buf.toString();
}
}
/**
* Returns a String representation of a given GPS mode
*
* @param mode
* GPS mode for which to retrieve a String
* @return String representation of GPS mode
*/
private String getGPSModeString(final int mode) {
final StringBuffer modeString = new StringBuffer();
if (mode == GPSInfo.GPS_MODE_ASSIST) {
modeString.append("*ASSIST");
}
if (mode == GPSInfo.GPS_MODE_AUTONOMOUS) {
modeString.append("*AUTONOMOUS");
}
if (mode == GPSInfo.GPS_MODE_BT) {
modeString.append("*BT");
}
if (mode == GPSInfo.GPS_MODE_CDMA_ACCURACY_OPTIMAL) {
modeString.append("*CDMA_ACCURACY_OPTIMAL");
}
if (mode == GPSInfo.GPS_MODE_CDMA_DATA_OPTIMAL) {
modeString.append("*CDMA_DATA_OPTIMAL");
}
if (mode == GPSInfo.GPS_MODE_CDMA_MS_ASSIST) {
modeString.append("*CDMA_MS_ASSIST");
}
if (mode == GPSInfo.GPS_MODE_CDMA_MS_BASED) {
modeString.append("*CDMA_MS_BASED");
}
if (mode == GPSInfo.GPS_MODE_CDMA_SPEED_OPTIMAL) {
modeString.append("*CDMA_SPEED_OPTIMAL");
}
if (mode == GPSInfo.GPS_MODE_CELLSITE) {
modeString.append("*CELLSITE");
}
if (mode == GPSInfo.GPS_MODE_NONE) {
modeString.append("*NONE");
}
if (mode == LocationInfo.GEOLOCATION_MODE_WLAN) {
modeString.append("*GEOLOCATION_MODE_WLAN");
} else if (mode == LocationInfo.GEOLOCATION_MODE_CELL) {
modeString.append("*GEOLOCATION_MODE_CELL");
} else if (mode == LocationInfo.GEOLOCATION_MODE) {
modeString.append("*GEOLOCATION_MODE");
}
modeString.append("*");
if (modeString.length() < 2) {
return "";
} else {
return modeString.toString();
}
}
/**
* Invoke the Maps application to show the fix on a map
*
* @param location
* The Location object to map
*/
private void displayLocationOnMap(final Location location) {
try {
String lon =
Double.toString(location.getQualifiedCoordinates()
.getLongitude() * 100000);
lon = lon.substring(0, 8);
String lat =
Double.toString(location.getQualifiedCoordinates()
.getLatitude() * 100000);
lat = lat.substring(0, 7);
final StringBuffer document =
new StringBuffer("<lbs><location lon='");
document.append(lon);
document.append("' lat='");
document.append(lat);
document.append("' label='MyLocation' zoom='");
document.append(_zoomLevelField.getText());
document.append("'/></lbs>");
Invoke.invokeApplication(Invoke.APP_TYPE_MAPS,
new MapsArguments(MapsArguments.ARG_LOCATION_DOCUMENT,
document.toString()));
} catch (final Exception e) {
log("Unable to map Location. Please make sure that BlackBerry Maps is installed.");
}
}
/**
* Resets the BlackBerryLocationProvider and removes reference
*/
public void stop() {
_isStopped = true;
// Log the statistics for the location session
log("Stopping Updates: " + formatDate(System.currentTimeMillis()));
log("Total Updates: " + _numberUpdatesField);
log("Assisted Updates: " + _numberAssistedUpdatesField);
log("Unassisted Updates: " + _numberUnassistedUpdatesField);
log("Valid Updates: " + _numberValidUpdatesField);
log("Invalid Updates: " + _numberInvalidUpdatesField);
if (_bbProvider != null) {
_bbProvider.setLocationListener(null, 0, 0, 0);
_bbProvider.reset();
_bbProvider = null;
}
}
/**
* Returns the running/stopped status of this thread
*
* @return The running/stopped status of this thread
*/
boolean isStopped() {
return _isStopped;
}
/**
* Returns a readable error message for a given GPS error code
*
* @param err
* Error code
* @return Human readable error message
*/
private String getErrorMessage(final int err) {
String msg = "";
switch (err) {
case GPSInfo.GPS_ERROR_ALMANAC_OUTDATED:
msg = "Almanac outdated";
break;
case GPSInfo.GPS_ERROR_AUTHENTICATION_FAILURE:
msg = "Authentication failed with the network";
break;
case GPSInfo.GPS_ERROR_CHIPSET_DEAD:
msg = "GPS chipset dead; no fix";
break;
case GPSInfo.GPS_ERROR_DEGRADED_FIX_IN_ALLOTTED_TIME:
msg = "Degraded fix; poor accuracy";
break;
case GPSInfo.GPS_ERROR_GPS_LOCKED:
msg = "GPS service locked";
break;
case GPSInfo.GPS_ERROR_INVALID_NETWORK_CREDENTIAL:
msg = "Invalid network credential";
break;
case GPSInfo.GPS_ERROR_INVALID_REQUEST:
msg = "Request is invalid";
break;
case GPSInfo.GPS_ERROR_LOW_BATTERY:
msg = "Low battery; fix cannot be obtained";
break;
case GPSInfo.GPS_ERROR_NETWORK_CONNECTION_FAILURE:
msg = "Unable to connect to the data network";
break;
case GPSInfo.GPS_ERROR_NO_FIX_IN_ALLOTTED_TIME:
msg = "No fix obtained in alloted time.";
break;
case GPSInfo.GPS_ERROR_NO_SATELLITE_IN_VIEW:
msg =
"No Satellite is in view or the signal strength is too low to get a position fix";
break;
case GPSInfo.GPS_ERROR_NONE:
msg = "No GPS Error";
break;
case GPSInfo.GPS_ERROR_PRIVACY_ACCESS_DENIED:
msg = "Privacy setting denies getting a fix";
break;
case GPSInfo.GPS_ERROR_SERVICE_UNAVAILABLE:
msg =
"GPS service is not available due to no cellular service or no data service or no resources, etc.";
break;
case GPSInfo.GPS_ERROR_TIMEOUT_DEGRADED_FIX_NO_ASSIST_DATA:
msg = "Degraded fix (no assist data); poor accuracy";
break;
case GPSInfo.GPS_ERROR_TIMEOUT_NO_FIX_NO_ASSIST_DATA:
msg = "No fix in alloted time, no assist";
break;
default:
msg = "Unknown error";
break;
}
return msg;
}
/**
* LocationListener implementation
*/
private class LocListener implements LocationListener {
/**
* @see javax.microedition.location.LocationListener#locationUpdated(LocationProvider,
* Location)
*/
public void locationUpdated(final LocationProvider provider,
final Location location) {
_bbLocation = (BlackBerryLocation) location;
if (_bbLocation != null) {
logLocation(_bbLocation);
} else {
log("Location is null");
}
}
/**
* @see javax.microedition.location.LocationListener#providerStateChanged(LocationProvider,
* int)
*/
public void providerStateChanged(final LocationProvider provider,
final int newState) {
switch (newState) {
case LocationProvider.OUT_OF_SERVICE: // Triggered when a BES
// policy does not allow
// location capabilities
log("State Change: Out of Service");
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE: // Triggered when
// the system has
// stopped
// looking for a
// fix
log("State Change: Temp Unavailable");
log("Resetting Location Provider due to TEMPORARILY UNAVAILABLE state");
_resetNow = true;
break;
}
}
}
}
}