Chapter 6: Integrating with the Hardware
Geolocation
All Windows Phone devices have built-in geolocation hardware. By using a combination of 3G, Wi-Fi, and GPS signal, the phone is able to identify the user’s location and make it available to every app, thanks to a set of APIs included in the Windows Runtime.
Geolocation is another scenario where APIs are duplicated. The original API set was part of the Silverlight framework, but it has been expanded in the Windows Runtime.
The new main class for working with geolocation services is called Geolocator, and it’s part of the Windows.Devices.Geolocation namespace.
Note: To use geolocation services, you’ll need to enable the ID_CAP_LOCATION capability in the manifest file.
The first step to use geolocation services is to check the LocationStatus property value of the Geolocator class to identify the current status of the services. Specifically, we have to manage the PositionStatus.Disabled status. In this case, the user has disabled the geolocation services in the phone’s settings, so we don’t have to execute any operation related to geolocation, otherwise we will get an exception. If you want to keep track of the geolocation service’s status, there’s a specific event handler called StatusChanged that is invoked every time the status changes. It helps you to identify, for example, that the GPS is ready or that the user is in a location that is hard to track.
There are two ways to interact with the Geolocator class: asking for a single position (for example, a Twitter client that needs to geolocalize a tweet), or subscribing to an event handler that can be used to continuously track the user’s location (for example, a running tracker app).
To ask for a single position, you simply have to call the asynchronous method GetGeopositionAsync(). It will return a Geoposition object containing a Coordinate property that will help you to identify where the user is.
Note: The Geoposition object has another property called CivicAddress which should contain a reference to the user’s location using civic references (like the city, street address, etc.). This property isn’t supported, so it will always return incorrect information. Later in this chapter we’ll look at how to get the civic position of the user.
The following code sample demonstrates how to get a single user’s position:
private async void OnGetSinglePositionClicked(object sender, RoutedEventArgs e)
{
Geolocator geolocator = new Geolocator();
if (geolocator.LocationStatus != PositionStatus.Disabled)
{
Geoposition geoposition = await geolocator.GetGeopositionAsync();
MessageBox.Show(string.Format("The user's coordinates are {0} - {1}", geoposition.Coordinate.Latitude, geoposition.Coordinate.Latitude))
}
}
To continuously track the user’s position, instead, you need to subscribe to the PositionChanged event handler, which is invoked every time the user moves from the previous location. You can control how often this event is raised by setting three properties of the Geolocator object:
The PositionChanged event returns a parameter that contains a Position property of type Geoposition-it works the same way as we’ve previously seen for the GetGeopositionAsync() method.
private void OnStartTrackingPosition(object sender, RoutedEventArgs e)
{
Geolocator geolocator = new Geolocator();
geolocator.MovementThreshold = 100;
geolocator.ReportInterval = 1000;
geolocator.DesiredAccuracy = PositionAccuracy.High;
geolocator.PositionChanged += geolocator_PositionChanged;
}
private void geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
{
Dispatcher.BeginInvoke(() =>
{
Latitude.Text = args.Position.Coordinate.Latitude.ToString();
Longitude.Text = args.Position.Coordinate.Longitude.ToString();
});
}
In the previous sample, we track the user’s location every time he or she moves 100 meters from the previous location, only if at least one second has passed since the previous detection. Every time the PositionChanged event is raised, we display the Latitude and Longitude properties’ values in two different TextBlock controls. Note that we’re using the Dispatcher class we discussed in Chapter 3. It’s required because the PositionChanged event is managed in a background thread, so we are not able to directly interact with the UI.