From b16e7800be4f879135f239f1f8f586f3712df01e Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 6 Aug 2009 09:26:02 -0400 Subject: gps: Add GpsStatus.NmeaListener interface for receiving NMEA sentences. NMEA sentences are passed from the GPS engine to the GpsLocationProvider. They are then sent via the IGpsStatusListener binder interface to clients using the same path as the other GPS status information. Signed-off-by: Mike Lockwood --- location/java/android/location/GpsStatus.java | 9 ++ .../java/android/location/IGpsStatusListener.aidl | 1 + .../java/android/location/LocationManager.java | 146 ++++++++++++++++++--- 3 files changed, 136 insertions(+), 20 deletions(-) (limited to 'location/java/android') diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java index 2cda7fa..883ee4f 100644 --- a/location/java/android/location/GpsStatus.java +++ b/location/java/android/location/GpsStatus.java @@ -115,6 +115,15 @@ public final class GpsStatus { void onGpsStatusChanged(int event); } + /** + * Used for receiving NMEA data from the GPS. + * + * {@hide} + */ + public interface NmeaListener { + void onNmeaReceived(long timestamp, String nmea); + } + GpsStatus() { for (int i = 0; i < mSatellites.length; i++) { mSatellites[i] = new GpsSatellite(i + 1); diff --git a/location/java/android/location/IGpsStatusListener.aidl b/location/java/android/location/IGpsStatusListener.aidl index 5dc0fe8..62b1c6b 100644 --- a/location/java/android/location/IGpsStatusListener.aidl +++ b/location/java/android/location/IGpsStatusListener.aidl @@ -29,4 +29,5 @@ oneway interface IGpsStatusListener void onSvStatusChanged(int svCount, in int[] prns, in float[] snrs, in float[] elevations, in float[] azimuths, int ephemerisMask, int almanacMask, int usedInFixMask); + void onNmeaReceived(long timestamp, String nmea); } diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index ca16f19..8f17e78 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -51,6 +51,8 @@ public class LocationManager { private ILocationManager mService; private final HashMap mGpsStatusListeners = new HashMap(); + private final HashMap mNmeaListeners = + new HashMap(); private final GpsStatus mGpsStatus = new GpsStatus(); /** @@ -1123,49 +1125,103 @@ public class LocationManager { private class GpsStatusListenerTransport extends IGpsStatusListener.Stub { private final GpsStatus.Listener mListener; + private final GpsStatus.NmeaListener mNmeaListener; + + // This must not equal any of the GpsStatus event IDs + private static final int NMEA_RECEIVED = 1000; + + private class Nmea { + long mTimestamp; + String mNmea; + + Nmea(long timestamp, String nmea) { + mTimestamp = timestamp; + mNmea = nmea; + } + } + private ArrayList mNmeaBuffer; GpsStatusListenerTransport(GpsStatus.Listener listener) { mListener = listener; + mNmeaListener = null; + } + + GpsStatusListenerTransport(GpsStatus.NmeaListener listener) { + mNmeaListener = listener; + mListener = null; + mNmeaBuffer = new ArrayList(); } public void onGpsStarted() { - Message msg = Message.obtain(); - msg.what = GpsStatus.GPS_EVENT_STARTED; - mGpsHandler.sendMessage(msg); + if (mListener != null) { + Message msg = Message.obtain(); + msg.what = GpsStatus.GPS_EVENT_STARTED; + mGpsHandler.sendMessage(msg); + } } public void onGpsStopped() { - Message msg = Message.obtain(); - msg.what = GpsStatus.GPS_EVENT_STOPPED; - mGpsHandler.sendMessage(msg); + if (mListener != null) { + Message msg = Message.obtain(); + msg.what = GpsStatus.GPS_EVENT_STOPPED; + mGpsHandler.sendMessage(msg); + } } public void onFirstFix(int ttff) { - mGpsStatus.setTimeToFirstFix(ttff); - Message msg = Message.obtain(); - msg.what = GpsStatus.GPS_EVENT_FIRST_FIX; - mGpsHandler.sendMessage(msg); + if (mListener != null) { + mGpsStatus.setTimeToFirstFix(ttff); + Message msg = Message.obtain(); + msg.what = GpsStatus.GPS_EVENT_FIRST_FIX; + mGpsHandler.sendMessage(msg); + } } public void onSvStatusChanged(int svCount, int[] prns, float[] snrs, float[] elevations, float[] azimuths, int ephemerisMask, int almanacMask, int usedInFixMask) { - mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths, - ephemerisMask, almanacMask, usedInFixMask); + if (mListener != null) { + mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths, + ephemerisMask, almanacMask, usedInFixMask); + + Message msg = Message.obtain(); + msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS; + // remove any SV status messages already in the queue + mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS); + mGpsHandler.sendMessage(msg); + } + } - Message msg = Message.obtain(); - msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS; - // remove any SV status messages already in the queue - mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS); - mGpsHandler.sendMessage(msg); + public void onNmeaReceived(long timestamp, String nmea) { + if (mNmeaListener != null) { + synchronized (mNmeaBuffer) { + mNmeaBuffer.add(new Nmea(timestamp, nmea)); + } + Message msg = Message.obtain(); + msg.what = NMEA_RECEIVED; + // remove any NMEA_RECEIVED messages already in the queue + mGpsHandler.removeMessages(NMEA_RECEIVED); + mGpsHandler.sendMessage(msg); + } } private final Handler mGpsHandler = new Handler() { @Override public void handleMessage(Message msg) { - // synchronize on mGpsStatus to ensure the data is copied atomically. - synchronized(mGpsStatus) { - mListener.onGpsStatusChanged(msg.what); + if (msg.what == NMEA_RECEIVED) { + synchronized (mNmeaBuffer) { + int length = mNmeaBuffer.size(); + for (int i = 0; i < length; i++) { + Nmea nmea = mNmeaBuffer.get(i); + mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea); + } + mNmeaBuffer.clear(); + } + } else { + // synchronize on mGpsStatus to ensure the data is copied atomically. + synchronized(mGpsStatus) { + mListener.onGpsStatusChanged(msg.what); + } } } }; @@ -1217,6 +1273,56 @@ public class LocationManager { } } + /** + * Adds an NMEA listener. + * + * @param listener NMEA listener object to register + * + * @return true if the listener was successfully added + * + * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present + * + * {@hide} + */ + public boolean addNmeaListener(GpsStatus.NmeaListener listener) { + boolean result; + + if (mNmeaListeners.get(listener) != null) { + // listener is already registered + return true; + } + try { + GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener); + result = mService.addGpsStatusListener(transport); + if (result) { + mNmeaListeners.put(listener, transport); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e); + result = false; + } + + return result; + } + + /** + * Removes an NMEA listener. + * + * @param listener NMEA listener object to remove + * + * {@hide} + */ + public void removeNmeaListener(GpsStatus.NmeaListener listener) { + try { + GpsStatusListenerTransport transport = mNmeaListeners.remove(listener); + if (transport != null) { + mService.removeGpsStatusListener(transport); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e); + } + } + /** * Retrieves information about the current status of the GPS engine. * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged} -- cgit v1.1