Location

Location user drivers allow your app to publish updates to the device's physical location through the Android location services. The API supports constellations of the Global Navigation Satellite System (GNSS), such as the Global Positioning System (GPS).

GNSS modules are receive-only devices that triangulate signals from remote satellites in order to determine an accurate physical location. Once the module collects enough satellite data to calculate an accurate position, it has a valid location (a fix ) that it can report.

Receiver modules typically connect to the host system via UART, but may use other forms of Peripheral I/O. For example, they may contain additional GPIO pins to control power management or report when the module has gained or lost a fix.

Adding the required permission

Add the required permission for the user driver to your app's manifest file:

<uses-permission android:name="com.google.android.things.permission.MANAGE_GNSS_DRIVERS" />

Creating the driver

The driver implementation is responsible for communicating with the connected hardware, monitoring for valid location changes, and reporting those changes to the framework. To create a driver:

  1. Create a new GnssDriver instance.
  2. Register the driver with the UserDriverManager:

    import com.google.android.things.userdriver.location.GnssDriver;
    import com.google.android.things.userdriver.UserDriverManager;
    ...
    
    public class LocationDriverService extends Service {
    
        private GnssDriver mDriver;
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            // Create a new driver implementation
            mDriver = new GnssDriver();
    
            // Register with the framework
            UserDriverManager manager = UserDriverManager.getInstance();
            manager.registerGnssDriver(mDriver);
        }
    
    }
    
  3. Unregister the driver when location events are not longer required.

    public class LocationDriverService extends Service {
        ...
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
    
            UserDriverManager manager = UserDriverManager.getInstance();
            manager.unregisterGnssDriver();
        }
    }
    

Reporting location

Report each new location fix to the Android framework with the reportLocation() method. This method accepts a Location object, which contains the updated contents to report. Set the provider for each reported Location to LocationManager.GPS_PROVIDER.

    import android.location.Location;
    ...

    public class LocationDriverService extends Service {

        private GnssDriver mDriver;
        ...

        private Location parseLocationFromString(String data) {
            Location result = new Location(LocationManager.GPS_PROVIDER);

            // ...parse raw GNSS information...

            return result;
        }

        public void handleLocationUpdate(String rawData) {
            // Convert raw data into a location object
            Location location = parseLocationFromString(rawData);

            // Send the location update to the framework
            mDriver.reportLocation(location);
        }
    }

The following table describes the Location attributes that a driver can report to the framework. Attributes marked required must be included or the framework will reject the location update:

Required Attributes Optional Attributes
Accuracy
Timestamp
Latitude
Longitude
Altitude
Bearing
Speed

Converting GPS data

GPS is a commonly used constellation of GNSS satellites. GPS hardware typically reports location information as ASCII strings in the NMEA standard format. Each line of data is a comma-separated list of data values known as a sentence. While each GPS module may choose to report different portions of the NMEA protocol, most devices send one or more of the following sentences:

  • GPGGA (Fix Information): Includes position fix, altitude, timestamp, and satellite metadata.
  • GPGLL (Geographic Latitude/Longitude): Includes position fix and timestamp.
  • GPRMC (Recommended Minimum Navigation): Includes position fix, speed, timestamp, and navigation metadata.

As an example, the GPRMC sentence takes the following format:


$GPRMC,<Time>,<Status>,<Latitude>,<Longitude>,<Speed>,<Angle>,<Date>,<Variation>,<Integrity>,<Checksum>

Using real data values, here is a sample GPRMC with the latitude, longitude, and speed portions highlighted in bold:


$GPRMC,172934.975,V,3554.931,N,07402.499,W,16.4,3.35,300816,,E*41

The following code example parses the GPRMC string format into a Location instance:

// Convert latitude from DMS to decimal format
private float parseLatitude(String latString, String hemisphere) {
    float lat = Float.parseFloat(latString.substring(2))/60.0f;
    lat += Float.parseFloat(latString.substring(0, 2));
    if (hemisphere.contains("S")) {
        lat *= -1;
    }
    return lat;
}

// Convert longitude from DMS to decimal format
private float parseLongitude(String longString, String hemisphere) {
    float lat = Float.parseFloat(longString.substring(3))/60.0f;
    lat += Float.parseFloat(longString.substring(0, 3));
    if (hemisphere.contains("W")) {
        lat *= -1;
    }
    return lat;
}

// Return a location from an NMEA GPRMC string
public Location parseLocationFromString(String rawData) {
    // Tokenize the string input
    String[] nmea = rawData.split(",");

    Location result = new Location(LocationManager.GPS_PROVIDER);
    // Create timestamp from the date + time tokens
    SimpleDateFormat format = new SimpleDateFormat("ddMMyyhhmmss.ss");
    format.setTimeZone(TimeZone.getTimeZone("UTC"));
    try {
        Date date = format.parse(nmea[9] + nmea[1]);
        result.setTime(date.getTime());
    } catch (ParseException e) {
        return null;
    }

    // Parse the fix information tokens
    result.setLatitude(parseLatitude(nmea[3], nmea[4]));
    result.setLongitude(parseLongitude(nmea[5], nmea[6]));
    result.setSpeed(Float.parseFloat(nmea[7]));

    return result;
}