BluetoothLocationProvider.java
Upload User: yfzsli
Upload Date: 2014-11-27
Package Size: 606k
Code Size: 13k
Category:

Jsp/Servlet

Development Platform:

Java

  1. package org.j4me.bluetoothgps;
  2. import java.io.*;
  3. import javax.microedition.io.*;
  4. import org.j4me.logging.*;
  5. /**
  6.  * Maps the communications with a Bluetooth GPS device to the <code>LocationProvider</code>
  7.  * interface.
  8.  */
  9. class BluetoothLocationProvider extends LocationProvider {
  10. /**
  11.  * The protocol portion of the URL for Bluetooth addresses.
  12.  */
  13. private static final String BLUETOOTH_PROTOCOL = "btspp://";
  14. /**
  15.  * The Bluetooth connection string options for communicating with a
  16.  * GPS device.
  17.  * <ul>
  18.  *  <li>master is false because the current device is the master
  19.  *  <li>encryption is false because no sensitive data is transmitted
  20.  *  <li>authentication is false because the data is not personalized
  21.  * </ul>
  22.  */
  23. private static final String BLUETOOTH_GPS_OPTIONS = ";master=false;encrypt=false;authenticate=false";
  24.     /**
  25.      * The instance of this class
  26.      */
  27.     private static BluetoothLocationProvider instance = null;
  28.     /**
  29.      * Holds the connection to the GPS device.  Used to get coordinates from the GPS device.
  30.      */
  31.     private BluetoothGPS gps = null;
  32.     /**
  33.      * URL used to connect
  34.      */
  35.     private String bluetoothURL = null;
  36.     /**
  37.      * The state of the location provider
  38.      */
  39.     private int state = TEMPORARILY_UNAVAILABLE;
  40.     /**
  41.      * Returns a <code>LocationProvider</code> for the GPS device connected to
  42.      * via Bluetooth.
  43.      */
  44. public static LocationProvider getInstance (Criteria criteria)
  45. throws LocationException, IOException
  46. {
  47. // Make sure we haven't given out our one Bluetooth GPS provider.
  48. //  Bluetooth will only support a connection to a single other GPS
  49. //  device so we cap out at one provider.
  50. if ( instance != null )
  51. {
  52. throw new LocationException("Bluetooth GPS socket already in use.");
  53. }
  54. // See if we meet the criteria.
  55. if ( matchesCriteria(criteria) )
  56. {
  57. String url = criteria.getRemoteDeviceAddress();
  58. return getInstance( url );
  59. }
  60. else
  61. {
  62. // Bluetooth GPS doesn't meet the criteria.
  63. return null;
  64. }
  65. }
  66.     
  67.     /**
  68.      * Construct the instance of this class.  If the <code>channelId</code> is <code>null</code>
  69.      * this method will attempt to guess at the channel id.
  70.      *
  71.      * @param remoteDeviceBTAddress - The remote GPS device bluetooth address
  72.      * @param channelId - The channel id for the remote device.  This may be <code>null</code>.  If this
  73.      *  is the case we will simply guess at the channel ID for the device.
  74.      * @throws ConnectionNotFoundException - If the target of the name cannot be found, or if the requested protocol type is not supported. 
  75.      * @throws IOException - If error occurs while establishing bluetooth connection or opening input stream. 
  76.      * @throws SecurityException - May be thrown if access to the protocol handler is prohibited.
  77.      */
  78.     private BluetoothLocationProvider(String remoteDeviceBTAddress,
  79.         String channelId) throws ConnectionNotFoundException, IOException, SecurityException {
  80.         
  81.      // The number of channels to try connecting on.
  82.      //  Bluetooth address have channels 1-9 typically.  However, GPS
  83.      //  devices seem to only have 1 channel.  We'll use two just to
  84.      //  be safe in case the Bluetooth GPS device allows multiple
  85.      //  connections.
  86.      final int maxTries = 2;
  87.     
  88.         // If the channel id is null, we need to guess at the channel id
  89.         if (channelId == null) {
  90.             // Try a few channels
  91.             for (int i = 1; i <= maxTries; i++) {
  92.                 try {
  93.                     bluetoothURL = constructBTURL(remoteDeviceBTAddress,
  94.                             Integer.toString(i));
  95.                     gps = connect(bluetoothURL);
  96.                     break;
  97.                 } catch (IOException e) {
  98.                     if (Log.isDebugEnabled()) {
  99.                         Log.debug("Channel ID = " + i + " failed:  " + e.toString());
  100.                     }
  101.                     // If there are still more to try, then try them
  102.                     if (i == maxTries) {
  103.                         throw e;
  104.                     }
  105.                 }
  106.             }
  107.         } else {
  108.             // Connect to the remote GPS device
  109.             bluetoothURL = constructBTURL(remoteDeviceBTAddress, channelId);
  110.             gps = connect(bluetoothURL);
  111.         }
  112.     }
  113.     
  114.     /**
  115.      * Returns if the Bluetooth GPS implementation matches the required
  116.      * criteria for the application.
  117.      * <p>
  118.      * Getting specific information about the Bluetooth GPS device is not
  119.      * possible without first connecting to it.  We assume it is a NMEA
  120.      * with SBAS (Satellite Based Augmentation System) such as WAAS.  These
  121.      * devices have the following properties:
  122.      * <ul>
  123.      *  <li>Horizontal accuracy within 1 meter (90% within 3).
  124.      *  <li>Altitude is given.
  125.      *  <li>Vertical accuracy within 3 meters (not positive).
  126.      *  <li>Response times of a second.  In actuality these
  127.      *      devices work at 4800 baud or more meaning they send at least
  128.      *      8 sentences a second (480 characters / 80 characters sentence).
  129.      *      Not all of these sentences give us the necessary data, but usually
  130.      *      it comes in a minimum of twice a second.
  131.      *  <li>Power consumption of medium (arguably high).  Bluetooth is a
  132.      *      battery draining medium.  However, just as with a Bluetooth headset for
  133.      *      voice, a phone will work for many hours on a single charge.
  134.      *  <li>No cost associated.  GPS and SBAS are free signals.
  135.      *  <li>Speed and course are given.
  136.      *  <li>Address information is not supplied.  Only the WGS 84 coordinates are
  137.      *      obtained.
  138.      *  <li>A remote URL, typically to a Bluetooth GPS device, must be supplied.
  139.      *      Otherwise only local LBS found on the device running this MIDlet are
  140.      *      allowed. 
  141.      * </ul>
  142.      * 
  143.      * @param criteria defines the applications LBS requirements.
  144.      * @return <code>true</code> if the Bluetooth GPS meets the specified criteria;
  145.      *  <code>false</code> if it does not.
  146.      */
  147.     public static boolean matchesCriteria (Criteria criteria)
  148.     {
  149.      if ( criteria.getHorizontalAccuracy() < 1 )  // in meters
  150.      {
  151.      return false;
  152.      }
  153.     
  154.      if ( criteria.isAltitudeRequired() && criteria.getVerticalAccuracy() < 1 )  // in meters
  155.      {
  156.      return false;
  157.      }
  158.     
  159.      if ( (criteria.getPreferredResponseTime() > 500) && (criteria.getPreferredResponseTime() < 500) )  // in milliseconds
  160.      {
  161.      return false;
  162.      }
  163.     
  164.      if ( criteria.getPreferredPowerConsumption() == Criteria.POWER_USAGE_LOW )
  165.      {
  166.      return false;
  167.      }
  168.     
  169.      if ( criteria.isAddressInfoRequired() )
  170.      {
  171.      return false;
  172.      }
  173.     
  174.      if ( criteria.getRemoteDeviceAddress() == null )
  175.      {
  176.      return false;
  177.      }
  178.     
  179.      // If we made it here all the criteria were met.
  180.      return true;
  181.     }
  182.     /**
  183.      * Get the instance of this class when the Bluetooth URL is known
  184.      *
  185.      * @param bturl - The url to the bluetooth device
  186.      * @throws ConnectionNotFoundException - If the target of the name cannot be found, or if the requested protocol type is not supported. 
  187.      * @throws IOException - If error occurs while establishing bluetooth connection or opening input stream. 
  188.      * @throws SecurityException - May be thrown if access to the protocol handler is prohibited.
  189.      */
  190.     public static BluetoothLocationProvider getInstance(String bturl)
  191.         throws ConnectionNotFoundException, IOException, SecurityException {
  192.         if (instance == null) {
  193.             instance = new BluetoothLocationProvider(bturl, null);
  194.         }
  195.         return instance;
  196.     }
  197.     /**
  198.      * Connect to the GPs device.
  199.      *
  200.      * @param bturl - The url to the bluetooth GPS device
  201.      * @throws ConnectionNotFoundException - If the target of the name cannot be found, or if the requested protocol type is not supported. 
  202.      * @throws IOException - If error occurs while establishing bluetooth connection or opening input stream. 
  203.      * @throws SecurityException - May be thrown if access to the protocol handler is prohibited.
  204.      */
  205.     private BluetoothGPS connect(String bturl)
  206.   throws ConnectionNotFoundException, IOException, SecurityException {
  207.      // Connect to the Bluetooth GPS device.
  208.         BluetoothGPS gps = new BluetoothGPS(this, bturl);
  209.         gps.start();
  210.         return gps;
  211.     }
  212.     /**
  213.  * Construct the Bluetooth URL
  214.  * 
  215.  * @param deviceBluetoothAddress - The address of the remote device
  216.  * @param channelId - The channel ID to use
  217.  */
  218. protected static String constructBTURL (String deviceBluetoothAddress, String channelId)
  219. {
  220. if ( (channelId == null) || (deviceBluetoothAddress == null) )
  221. {
  222. return null;
  223. }
  224. StringBuffer url = new StringBuffer();
  225. // Add the "btspp://" prefix (if not already there).
  226. if ( deviceBluetoothAddress.substring(0, BLUETOOTH_PROTOCOL.length())
  227. .equalsIgnoreCase(BLUETOOTH_PROTOCOL) == false )
  228. {
  229. url.append( BLUETOOTH_PROTOCOL );
  230. }
  231. // Add the address.
  232. url.append( deviceBluetoothAddress );
  233. // Add the channel ID (if not already there).
  234. if ( deviceBluetoothAddress.indexOf(':', BLUETOOTH_PROTOCOL.length() + 1) < 0 )
  235. {
  236. url.append( ':' );
  237. url.append( channelId );
  238. }
  239. // Add the Bluetooth options (if not already there).
  240. if ( deviceBluetoothAddress.indexOf(';') < 0 )
  241. {
  242. url.append( BLUETOOTH_GPS_OPTIONS );
  243. }
  244. String bturl = url.toString();
  245. return bturl;
  246. }
  247.     /**
  248.  * @see org.j4me.bluetoothgps.LocationProvider#getState()
  249.  */
  250.     public int getState() {
  251.         return state;
  252.     }
  253.     
  254.     /**
  255.      * Set the state of the location provider
  256.      * 
  257.      * @param state the location provider's state
  258.      */
  259.     public void setState(int state) {
  260.      this.state = state;
  261.     }
  262.     
  263. /**
  264.  * @see org.j4me.bluetoothgps.LocationProvider#getLocation(int)
  265.  */
  266. public Location getLocation (int timeout)
  267. throws LocationException, InterruptedException
  268. {
  269. if ( (timeout == 0) || (timeout < -1) )
  270. {
  271. throw new IllegalArgumentException();
  272. }
  273. long start = System.currentTimeMillis();
  274. timeout *= 1000;  // Convert seconds to milliseconds.
  275. // Poll for the timeout period trying to get a location.
  276. Location loc;
  277. do
  278. {
  279. if ( (state == OUT_OF_SERVICE) || (gps == null) )
  280. {
  281. throw new LocationException("Bluetooth location provider is out of service");
  282. }
  283. // Get the last known location.
  284. loc = gps.getLastKnownLocation();
  285. if ( loc == null )
  286. {
  287. Thread.sleep( 250 );
  288. if ( System.currentTimeMillis() - start > timeout)
  289. {
  290. throw new LocationException("Timed out getting location from Bluetooth location provider");
  291. }
  292. }
  293. } while ( loc == null );
  294. return loc;
  295. }
  296. /**
  297.  * Returns the last known location by the provider.
  298.  * 
  299.  * @return a location object. <code>null</code> is returned if the implementation
  300.  *  doesn't have any previous location information.
  301.  * @throws SecurityException - if the calling application does not have a
  302.  *  permission to query the location information
  303.  * 
  304.  * @see LocationProvider#getLastKnownLocationToProvider()
  305.  */
  306. protected Location getLastKnownLocationToProvider ()
  307. {
  308. return gps.getLastKnownLocation();
  309. }
  310.     /**
  311.      * @see org.j4me.bluetoothgps.LocationProvider#setLocationListener(org.j4me.bluetoothgps.LocationListener, int, int, int)
  312.      */
  313.     public void setLocationListener(LocationListener locationlistener,
  314.         int interval, int timeout, int maxAge) {
  315.         gps.setLocationListener(locationlistener, interval, timeout, maxAge);
  316.     }
  317.     /**
  318.      * @return The address of the Bluetooth GPS device.
  319.      */
  320.     public String getBluetoothURL() {
  321.         return bluetoothURL;
  322.     }
  323. /**
  324.  * Forces the Bluetooth GPS to re-acquire its location fix (which may take
  325.  * almost 40 seconds) and resets the Bluetooth connection.  This is helpful
  326.  * in making sure the connection is both properly working and getting an
  327.  * accurate reading.
  328.  * 
  329.  * @see org.j4me.bluetoothgps.LocationProvider#reset()
  330.  */
  331. public void reset ()
  332. throws IOException
  333. {
  334. if ( gps != null )
  335. {
  336. // Perform a warm-start on the GPS receiver so that it re-acquires a fix.
  337. gps.reacquireFix();
  338. // Mark the provider as unavailable.
  339. gps.setProviderState( TEMPORARILY_UNAVAILABLE );
  340. }
  341. }
  342.     /**
  343.      * @see org.j4me.bluetoothgps.LocationProvider#close()
  344.      */
  345.     public void close() {
  346.         if (gps != null) {
  347.      gps.stop();
  348.             
  349. // Record we are no longer connected.
  350.             state = OUT_OF_SERVICE;
  351.             
  352.             // Stop sending notifications.
  353.             gps.setLocationListener( null, -1, -1, -1 );
  354.         }
  355.     }
  356. }