A new geographic location API is
included with the Windows Phone 8 SDK. This WinPRT API supersedes the
Windows Phone 7 .NET API that relies on the GeoCoordinateWatcher
class. Although the .NET API is still supported, for new apps it is recommended that you use the new Geolocator
class that is part of the new WinPRT API. The new WinPRT geo location API has many similarities with the .NET API.
The new geographic location API is located in the namespace Windows.Devices.Geolocation
.
Geolocator Class
The Geolocator
class can be used by your app to monitor the location of the phone. It
contains events for monitoring hardware state changes and geographic
position changes.
Retrieving the Current Location
Geolocator
allows you to track the phone’s location, using its PositionChanged
event, and to retrieve the phone’s current location using its GetGeopositionAsync
method.
The GetGeopositionAsync
method forgoes the need to subscribe to the PositionChanged
event when all you need is a single reading. With GetGeopositionAsync
you can use the await keyword to conveniently wait for the method to return the Geoposition
result, as shown in the following example:
var geolocator = new Geolocator();
Geoposition geoposition = await geolocator.GetGeopositionAsync();
Geocoordinate geocoordinate = geoposition.Coordinate;
Note
When attempting to call the Geolocator
object’s GetGeopositionAsync
method, if location is disabled in the phone’s settings, an UnauthorizedAccessException
is raised.
Note
The Coordinate property of the Geoposition
class is of type Windows.Devices.Geolocation.Geocoordinate
, which is not to be confused with the System.Device.Location.GeoCoordinate
class. Notice the capital “C” in the latter type name.
Other types, such as the Geoposition
class, use the same casing pattern to indicate that they belong to the WinPRT API and not the .NET API.
The .NET GeoCoordinate type (and not the
WinPRT Geocoordinate type) is used heavily by the phone’s mapping API. Converting between the two types
is a matter of copying over the various property values. Listing 1 shows an extension method that is used to convert a WinPRT Geocoordinate
into a .NET GeoCoordinate
.
LISTING 1. GeocoordinateExtensions.ToGeoCoordinate
Method
static class GeocoordinateExtensions
{
public static GeoCoordinate ToGeoCoordinate(this Geocoordinate geocoordinate)
{
return new GeoCoordinate
(
geocoordinate.Latitude,
geocoordinate.Longitude,
geocoordinate.Altitude ?? Double.NaN,
geocoordinate.Accuracy,
geocoordinate.AltitudeAccuracy ?? Double.NaN,
geocoordinate.Speed ?? Double.NaN,
geocoordinate.Heading ?? Double.NaN);
}
}
The Geoposition
result of the GetGeopositionAsync
method potentially represents a cached reading. Caching the reading
saves the geo location infrastructure from having to engage hardware
components. GetGeopositionAsync
has a method overload that allows you to specify the maximum age of the
cached reading and the maximum number of seconds that the OS should
wait to get a location result before timing out and raising an
exception.
Best Practices
It is recommended that you use the GetGeopositionAsync
method when tracking is not required because it results in better battery life and, therefore, a better user experience.
DesiredAccuracy Property
Geolocator
allows you to request a desired accuracy level via its DesiredAccuracy
property, which can be set to either the default accuracy level, which
lets the OS decide the accuracy level, or a high accuracy level, which
causes the OS to prefer the accuracy of GPS. To create a Geolocator
that uses the default accuracy setting, use the following:
Geolocator defaultAccuracyLocator = new Geolocator();
For high accuracy, set the DesiredAccuracy
property like so:
Geolocator highAccuracyLocator
= new Geolocator {DesiredAccuracy = PositionAccuracy.High};
The PositionAccuracy
enum has the following two values:
- Default—Results
in a power optimized (or low power) configuration at the probable cost
of decreased accuracy. Moreover, the phone device favors the use of
cell tower triangulation and Wi-Fi triangulation above GPS.
- High—Favors GPS when available at the cost of greater power usage and, thus, reduced battery life.
Best Practices
Use the default (power optimized) accuracy
setting unless a higher level of accuracy is required. Using lower
accuracy minimizes power consumption, thereby increasing battery life.
DesiredAccuracyInMeters Property
In addition to the DesiredAccuracy
property, Geolocator
includes a DesiredAccuracyInMeters
property, which is not present in the older GeoCoordinateWatcher
API. The DesiredAccuracyInMeters
property is a nullable unsigned integer value that lets the OS choose
the mechanism for geo location. Lower values cause the phone to prefer
the accuracy of GPS.
Setting the DesiredAccuracyInMeters
property to a non-null value overrides the DesiredAccuracy
property.
MovementThreshold Property
In some environments, signal noise can cause
a GPS device to register movement when there is no movement. This can
be caused by surface reflection, which occurs when signals bounce
off walls or other structures, or by other environmental factors. It is
also exacerbated by the absence of a GPS antenna on Windows Phone
devices.
The MovementThreshold
property of the Geolocator
allows you to specify the minimum amount of movement required to
register a change in position. When a change is registered, the Geolocator
’s PositionChanged
event is raised.
MovementThreshold
is a double
value, which indicates the distance in meters, relative to the last coordinate received. The MovementThreshold
property allows position change notifications to be smoothed. If the value is set too low, the PositionChanged
event may be raised too frequently, or when there is no actual change
in location. Conversely, setting the value too high reduces the ability
of the device to provide up-to-date location coordinates. A road
navigation app, for example, with a MovementThreshold
value set too high, may cause a user to miss a turn. Set too low, the
application may provide continuous directions when the phone is, in
fact, stationary.
Tip
Setting the Geolocator.MovementThreshold
property to at least 20 helps to smooth out the signal, causing the PositionChanged
event to be raised only when the location has changed significantly.
Monitoring Position Changes
The Geolocator
class exposes the following two events:
- PositionChanged—This event is raised when a change in location is detected.
- StatusChanged—This
event is raised when the underlying location service changes state; for
example, when the location component is receiving data or when it has
been disabled.
PositionChanged Event
The PositionChanged
event is raised whenever a significant change is detected in the
phone’s location. How large the change needs to be is determined by the
Geolocator
object’s MovementThreshold
property.
The following code fragment demonstrates how to subscribe to the PositionChanged
event:
geolocator.PositionChanged += HandlePositionChanged;
When the PositionChanged
event is raised, the handler receives a PositionChangedEventArgs
object that contains a Geoposition
property, as shown:
void HandlePositionChanged(
Geolocator sender, PositionChangedEventArgs e)
{
Geoposition geoposition = e.Position;
Geocoordinate geocoordinate = geoposition.Coordinate;
CivicAddress civicAddress = geoposition.CivicAddress;
}
The Position
property of the PositionChangedEventArgs
is a Geoposition
instance containing the following two properties:
- Coordinate
(of type Geocoordinate
)
- CivicAddress
(of type CivicAddress
In the context of the geo location API, a position can be thought of as a location at a point in time. Geocoordinate
includes a Timestamp
property of type DateTimeOffset
, which indicates when the reading was taken.
Best Practices
Geolocator
leverages phone hardware that consumes power. Subscribe to its PositionChanged
event only when it is needed by your app, and unsubscribe as soon as it
is no longer needed. This reduces power consumption and increases the
battery life of the phone.
StatusChanged Event
The status of the underlying geographic location component is indicated by the Geolocator
object’s LocationStatus
property, which is of type PositionStatus
. PositionStatus
is an enum that contains the following values:
- Disabled—The location provider is disabled. No position updates occur.
- Initializing—The location provider is initializing. This status occurs, for example, when the GPS component is obtaining a fix.
- NoData—No location data is available from any location provider.
- NotAvailable—The
Windows Sensor and Location Platform is not available on the device.
The minimum Windows Phone hardware requirements preclude this status.
- NotInitialized—An operation to retrieve location has not yet been initialized. LocationStatus
will have this value if the application has not yet called GetGeopositionAsync
or registered an event handler for the PositionChanged
event.
- Ready—A location provider is ready to supply new data. In this state, the Geolocator
is able to raise its PositionChanged
event.
The location provider transitions between these states, as depicted in Figure 1.
FIGURE 1 Geolocator
transitions between PositionStatus
values.
When the Geolocator
object’s StatusChanged
event is raised, the handler receives a StatusChangedEventArgs
object, as shown in the following excerpt:
void HandleStatusChanged(Geolocator sender, StatusChangedEventArgs args)
{
PositionStatus status = args.Status;
switch (status)
{
case PositionStatus.Disabled:
// ...
break;
case PositionStatus.Initializing:
// ...
break;
case PositionStatus.NoData:
// ...
break;
case PositionStatus.NotInitialized:
// ...
break;
case PositionStatus.Ready:
// ...
break;
}
}