This blog post was authored by Daniel Estrada Alva, a software development engineer on the Windows Phone team.
- Adam
With the new set of Geolocation APIs in Windows Phone 8, your app can request a single position at any time, which means more flexibility as you develop your app. This post describes the new API for single position acquisition, with examples to show you how you can use the APIs to declare your needs to the Geolocator object.
How to use single position acquisition
The following code example demonstrates how to use the new Geolocation APIs:
- publicasyncTask
Geocoordinate> GetSinglePositionAsync() - {
- Windows.Devices.Geolocation.Geolocator geolocator = new Windows.Devices.Geolocation.Geolocator();
- Windows.Devices.Geolocation.Geoposition geoposition = await geolocator.GetGeopositionAsync();
- return geoposition.Coordinate;
- }
When the GetSinglePositionAsync method is called, it creates a new Geolocator object. Then, the code uses the Geolocator object to determine the geoposition. The geoposition is determined in the background, using the Windows Runtime (WinRT) asynchronous pattern. When the geoposition has been determined, the method returns the coordinates as the latitude and longitude associated with the geographic location.
This code works for most cases, in which the app usually only needs to know the current location. However, sometimes an app has certain requirements—such as accuracy—for the position it needs. With the new Geolocation APIs you can set those requirements using the following properties:
Parameter | Brief description |
Desired Accuracy | A best-effort approach satisfies the accuracy requirement of the app. This can be expressed either through an enumeration or through a scalar value (in meters). |
Timeout | The maximum time the Geolocator object has to obtain a position that satisfies the accuracy requirement. When the timeout is exhausted, the Geolocator object returns the best position it could obtain (even if this doesn’t satisfy the desired accuracy value), or an error if it wasn’t able to acquire any location. |
Maximum Age | You can use this new parameter to get a cached position that was obtained by the Geolocator object in the past, and to define a limit of how old that position can be for the app to use it. The cached position will only be returned if the age and accuracy requirements are met. |
The following sections expand on each of the properties, how an app can use them, and the set of combinations that will result in error conditions.
Defining the desired accuracy in a request
By default, any request will use an accuracy defined by Windows.Devices.Geolocation.PositionAccuracy.Default, which when possible avoids using the most power-intensive technologies to acquire the Geoposition. This approach works well for most apps, which have the simple requirements of knowing the approximate location of the phone. In addition, it often improves the overall user experience because the app may get the position faster with lower power consumption. However, in some circumstances an app needs a higher level of accuracy. In those cases you can set the desired accuracy in the following way:
- publicasyncTask
Geocoordinate> GetSinglePositionAsync() - {
- Windows.Devices.Geolocation.Geolocator geolocator = new Windows.Devices.Geolocation.Geolocator();
- geolocator.DesiredAccuracy = Windows.Devices.Geolocation.PositionAccuracy.High;
- Windows.Devices.Geolocation.Geoposition geoposition = await geolocator.GetGeopositionAsync();
- return geoposition.Coordinate;
- }
This approach uses the Windows.Deviced.Geolocation.PositionAccuracy enumeration in Windows Phone 8, which resembles the System.Device.Location.GeoPositionAccuracy enumeration in Windows Phone 7.
It’s also possible to define the accuracy requirements using the DesiredAccuracyInMeters property, through which you can set the target accuracy in meters, in the following way:
- publicasyncTask
Geocoordinate> GetSinglePositionAsync() - {
- Windows.Devices.Geolocation.Geolocator geolocator = new Windows.Devices.Geolocation.Geolocator();
- geolocator.DesiredAccuracyInMeters = 100;
- Windows.Devices.Geolocation.Geoposition geoposition = await geolocator.GetGeopositionAsync();
- return geoposition.Coordinate;
- }
Note that the DesiredAccuracyInMeters property is a nullable unsigned integer. This way you can switch from one representation of accuracy to another. When DesiredAccuracyInMeters is set (not null), it takes precedence over DesiredAccuracy. When DesiredAccuracyInMeters is not set (is null), DesiredAccuracy takes precedence. In addition, explicitly setting the DesiredAccuracy property has the side effect of setting DesiredAccuracyInMeters to null.
Using Timeout and MaximumAge in a request
Before going through an example of how you can set these parameters, I want to elaborate on the concept of MaximumAge and how it differs from Timeout.
Timeout is the period of time the request has to complete from the point the operation is started. By default, the request has no timeout.
MaximumAge defines a limit of how old a cached Geoposition can be, from the time the operation starts, for it to be used by the app. By default, the request will not return a cached Geoposition. If your app can use cached positions for a brief period of time, this parameter also can be seen as the validity time span. The app can simplify its logic by letting the Geolocator handle the caching.
For example, if the app sets MaximumAge to 5 minutes, the Geolocator can satisfy that request with a Geoposition that is as old as 5 minutes from the time the request is started, as long as that position meets the accuracy requirement specified by the app.
Note that the Geolocator will always take the following sequential steps to satisfy a request:
- The request is started.
- Identify whether a cached Geoposition satisfies the age and desired accuracy, and if so, immediately return it.
- Trigger positioning technologies based on the desired accuracy.
- Return a Geoposition when it meets the desired accuracy.
- When the timeout is reached, if no position is available yet, error out. If there is a position available, given that the framework follows a best-effort model, this Geoposition with a lower accuracy than desired by the app can be returned at this time. The app can decide whether the information is useful or to discard it.
The following timeline shows the sequence of operations. The first Geoposition from the left, which is already cached with the Geolocator,is too old for the age requirement and therefore is invalid in the context of the given request. The second Geoposition from the left could satisfy the request given the age requirement, but does not satisfy the desired accuracy so a more accurate position is detected. This final Geoposition satisfies the accuracy requirement and is returned to the app.
The following code snippet shows you how to pass these parameters to the Geolocator for a given request. For accuracy, the code builds on top of the preceding example. Also, please note that using named parameters is not necessary; I’ve used them in this example to make the code more readable.
- publicasyncTask
Geocoordinate> GetSinglePositionAsync() - {
- Windows.Devices.Geolocation.Geolocator geolocator = new Windows.Devices.Geolocation.Geolocator();
- geolocator.DesiredAccuracyInMeters = 100;
- Windows.Devices.Geolocation.Geoposition geoposition = await geolocator.GetGeopositionAsync(
- maximumAge: TimeSpan.FromMinutes(1),
- timeout: TimeSpan.FromSeconds(30)
- );
- return geoposition.Coordinate;
- }
Please note that setting desired accuracy is not required to use MaximumAge and Timeout.
The relationship between Accuracy, Timeout, and MaximumAge
When you build an app that specifies a desired accuracy, consider the following:
· In general, acquiring a Geoposition with a higher accuracy takes longer. With that in mind, if you are specifying a high desired accuracy, consider increasing the Timeout associated with the request.
· If a quick response time is important, consider specifying a lower desired accuracy and increase the maximum age.
If your app desires high-accuracy positions with a short timeout, consider using error handling that falls back to request a value with lower accuracy. You should also consider giving more time to the first request, and then reducing the timeout for subsequent requests.
MaximumAge and Accuracy also are related because the original accuracy of any given Geoposition fades as time passes. The Geolocator takes this into consideration when evaluating known information, and only considers the accuracy of information to be valid for a given time span.
You should design your app to check the accuracy and time stamp of positions returned by the framework, and then decide whether to use or to discard the data.