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