GeoClue2

Eckhart Wörner ewoerner at kde.org
Sun Apr 17 08:49:31 PDT 2011


Hi everybody,

when I first encountered GeoClue some time ago, I immediately liked the idea of 
it. However, I was somehow never really satisfied with its design. Therefore, 
in the last few days I tried to write down my vision of how its D-Bus API 
should look like, and now present it here for discussion. I'll start with the 
problems the old API has in my eyes, and then present a new API that hopefully 
overcomes these problems.

I'll call the old API GeoClue and my API GeoClue2 only to differentiate between 
them, not because I think that my API is perfect (it probably isn't). It also 
probably helps my subject getting some attention. ;-)


== Problems ==

The GeoClue API is incomplete: GeoClue Position and Velocity provide the 
coordinates of a point (which normally represents a device so close to the 
user's coordinates that we define them to be the user's coordinates) in a 
three-dimensional room (Latitude, Longitude, Altitude), and the first 
derivative (Speed, Direction, Climb). However, we still don't know the 
orientation of the device in this room.
Why may this information be useful? E.g. a routing application for pedestrians 
can rotate the map it displays according to the heading of the device.

The GeoClue API defines several providers and puts arbitrary borders between 
them: Latitude, Longitude and Altitude share the same provider, while Speed, 
Direction and Climb share a different provider, however, e.g. an altimeter only 
provides Altitude and Climb.

The GeoClue API is overly complex in some places: to get latitude, longitude 
and speed, one has to traverse two objects, and then use two different 
providers.

The GeoClue API exposes too much information to an application that uses it: 
an application that relies on the *type* of the underlying provider clearly 
does something wrong. An application should not decide which provider to use, 
instead GeoClue2 should. An application should not configure providers, a 
dedicated interface should do that.

The GeoClue API does not differentiate between an application that needs some 
piece of information to work properly, and a piece of information that is 
nice-to-have, but not necessary. E.g. an application for navigation clearly 
needs coordinates to work properly, while a weather applet that works fine 
without coordinates might still use them when they are available.

Applications may be interested in the last known value for some piece of 
information, even though it is not valid anymore.

The GeoClue API does not cope well with unexpected application behavior like 
crashes. E.g. AddReference and RemoveReference are just asking for problems.

The GeoClue API does not play well with D-Bus: Long-running methods will break 
as D-Bus puts a timeout on method calls.


== Proposal ==

The GeoClue2 service is the only access point to information; there's no 
documented way of communicating with individual providers for information 
retrieval.

The main interface allows to create objects for individual applications. Any 
object created through the main interface is said to be owned by the 
respective application and should not be used by any other application.

This is the main interface:

<node>
	<interface name="org.freedesktop.Geoclue2">

		<method name="CreateProvider">
			<arg name="path" type="o" direction="out" />
		</method>

		<method name="CreateAddressResolver">
			<arg name="path" type="o" direction="out" />
		</method>

		<method name="CreateCoordinatesResolver">
			<arg name="path" type="o" direction="out" />
		</method>

	</interface>
</node>

The CoordinatesResolver is responsible for resolving coordinates to an 
address. It is used by (optionally) first setting the TargetAccuracy and then 
calling Resolve with the coordinates.
If the resolving succeeds, the Result signal is emitted. If there is a 
permanent error resolving the coordinates, Error is emitted. An error is not 
signalled when it's only temporary. Applications which want a fixed timeout 
have to take care of this for themselves.
Destroy cancels the ongoing operation and destroys the object; an application 
must be prepared to handle the Result and Error signals after Destroy has been 
called due to the asynchronous nature of D-Bus.
Destroy is implicitly called when the application that created the resolver 
leaves the bus.

<node>
	<interface name="org.freedesktop.Geoclue2.CoordinatesResolver">

		<method name="Resolve">
			<arg name="latitude" type="d" direction="in" />
			<arg name="longitude" type="d" direction="in" />
			<arg name="altitude" type="d" direction="in" />
			<arg name="targetAccuracy" type="s" direction="in" />
		</method>
		
		<signal name="Result">
			<arg name="countryCode" type="s" />
			<arg name="country" type="s" />
			<arg name="region" type="s" />
			<arg name="locality" type="s" />
			<arg name="area" type="s" />
			<arg name="postalCode" type="s" />
			<arg name="street" type="s" />
		</signal>

		<signal name="Error" />

		<method name="Destroy" />

	</interface>
</node>

The AddressResolver is responsible for resolving an address to coordinates. It 
is used by (optionally) first setting the TargetAccuracy and then calling 
Resolve with the address.
If the resolving succeeds, the Result signal is emitted. If there is a 
permanent error resolving the address, Error is emitted. An error is not 
signalled when it's only temporary. Applications which want a fixed timeout 
have to take care of this for themselves.
Destroy cancels the ongoing operation and destroys the object; an application 
must be prepared to handle the Result and Error signals after Destroy has been 
called due to the asynchronous nature of D-Bus.
Destroy is implicitly called when the application that created the resolver 
leaves the bus.

<node>
	<interface name="org.freedesktop.Geoclue2.AddressResolver">

		<method name="Resolve">
			<arg name="countryCode" type="s" direction="in" />
			<arg name="country" type="s" direction="in" />
			<arg name="region" type="s" direction="in" />
			<arg name="locality" type="s" direction="in" />
			<arg name="area" type="s" direction="in" />
			<arg name="postalCode" type="s" direction="in" />
			<arg name="street" type="s" direction="in" />
			<arg name="targetAccuracy" type="s" direction="in" />
		</method>
		
		<signal name="Result">
			<arg name="Latitude" type="s" />
			<arg name="Longitude" type="s" />
			<arg name="Altitude" type="s" />
		</signal>

		<signal name="Error" />

		<method name="Destroy" />

	</interface>
</node>

The Provider (yes, I know this is not the best name) is responsible for 
providing information about aspects of the position of the device. These 
include:
- CountryCode, Country, Region, Locality, Area, PostalCode, Street
- Latitude, Longitude as WGS84 coordinates
- Altitude in meters above the reference surface of the WGS84 ellipsoid
- Heading as the angle between the projection of the main direction of the 
device on a tangential plane and true north, in degrees
- Elevation as the arc between the main direction of the device and a 
tangential plane, in degrees
- Bank as the rotation on the plane defined by heading and elevation, in 
degrees
- Speed and Direction as vector length and vector direction of the first 
derivative of (Latitude, Longitude), in km/h (?) and degrees, respectively
- Climb as first derivative of Altitude, in m/s

The above properties are considered as not set if they contain a value that is 
not in the allowed range of values, these ranges are to be defined. If they are 
set, they contain the last valid value. One can check whether the value is 
valid via the corresponding …Valid property.

An application indicates that it needs one or more properties to function 
correctly by setting ActiveProperties to the corresponding property names.

An application indicates that one or more properties may enhance the 
application's functionality without being needed to function correctly by 
setting PassiveProperties to the corresponding property names. GeoClue2 
ensures that PassiveProperties is always a superset of ActiveProperties by 
extending PassiveProperties as needed.

GeoClue2 may try to fill properties that are only in the PassiveProperties set 
at its own discretion; it is suggested that GeoClue2 provides those values iff 
they are in the ActiveProperties of another Provider.

Communication of changes is done via the standardized PropertiesChanged 
signal.

Destroy destroys the object; an application must be prepared to handle the 
PropertiesChanged signal after Destroy has been called due to the asynchronous 
nature of D-Bus.
Destroy is implicitly called when the application that created the provider 
leaves the bus.

<node>
	<interface name="org.freedesktop.Geoclue2.Provider">

		<property name="TargetAccuracy" type="s" access="readwrite" />

		<property name="ActiveProperties" type="as" access="readwrite" />
		<property name="PassiveProperties" type="as" access="readwrite" />

		<!-- Aspects of position (and first derivative) in 3d -->
		<property name="Latitude" type="d" access="read" />
		<property name="Longitude" type="d" access="read" />
		<property name="Altitude" type="d" access="read" />
		<property name="Heading" type="d" access="read" />
		<property name="Elevation" type="d" access="read" />
		<property name="Bank" type="d" access="read" />

		<property name="Speed" type="d" access="read" />
		<property name="Direction" type="d" access="read" />
		<property name="Climb" type="d" access="read" />

		<property name="CountryCode" type="s" access="read" />
		<property name="Country" type="s" access="read" />
		<property name="Region" type="s" access="read" />
		<property name="Locality" type="s" access="read" />
		<property name="Area" type="s" access="read" />
		<property name="PostalCode" type="s" access="read" />
		<property name="Street" type="s" access="read" />

		<property name="LatitudeValid" type="b" access="read" />
		<property name="LongitudeValid" type="b" access="read" />
		<property name="AltitudeValid" type="b" access="read" />
		<property name="HeadingValid" type="b" access="read" />
		<property name="ElevationValid" type="b" access="read" />
		<property name="BankValid" type="b" access="read" />

		<property name="SpeedValid" type="b" access="read" />
		<property name="DirectionValid" type="b" access="read" />
		<property name="ClimbValid" type="b" access="read" />

		<property name="CountryCodeValid" type="b" access="read" />
		<property name="CountryValid" type="b" access="read" />
		<property name="RegionValid" type="b" access="read" />
		<property name="LocalityValid" type="b" access="read" />
		<property name="AreaValid" type="b" access="read" />
		<property name="PostalCodeValid" type="b" access="read" />
		<property name="StreetValid" type="b" access="read" />

		<method name="Destroy" />

		<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal"
			value="true" />

	</interface>
</node>

Configuration is separated from the main functionality. It should not be used 
by an application, but only by a configuration tool. The interface is yet to be 
defined.

As said, this API is only a draft for a redesign, and I'd therefore like to 
see tons of comments, criticism, flames, whatever ;-)

Eckhart


More information about the GeoClue mailing list