Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using Windows Phone Location Services

0.00/5 (No votes)
30 Nov 2011 1  
A quick write up on location services.

Introduction

I was assisting some college students at a Microsoft event on the Georgia Tech campus. Some questions about location services came up. A few days later I was assisting some other college students in the Microsoft Windows Phone Development Forums and some of the same questions came up. So I've decided to do a quick write up on location services to have as a reference the next time the question comes up.

image.png

I'll cover what needs to be done to get the user's location and formatting it for the screen.

How Does Windows Phone Acquire my Location

Windows Phone uses three technologies for finding your location; GPS, WiFi based location, and Cell Tower based location. The technology with which most are familiar is GPS. In a nutshell GPS technology relies on satellites in orbit and the phone's ability to receive signals from at least three of these satellites. These satellites are all transmitting the time from synchronized clocks. But because of the satellites being different distances from the phone the time received from the satellites will be slightly different (since the further away the satellite is from the user the more time it takes for the signal to be received). A user's position can be calulated from these time differences.

Cell Tower based location and WiFi based location are similar in how they work. When you use either one of these the phone will try to get the identifiers for near by WiFi access points and cell towers. The identifier is sent to a Microsoft service which keeps records of the general area in which those WiFi access points or cell towers have been seen and returns that information to the device. This information isn't static; cell towers can be taken down and new towers can be built and when people move to new apartments and houses they take their access points with them. To keep their information up to date Microsoft acquires new information from vehicles driving around as a part of the StreetSide Project and also receives data from other phones that are using location services. If a phone is able to get location from GPS and also sees a new access point then that access point is reported as having been seen at that location.

I've got a bad habit of generically referring to any type of location service as GPS. This isn't correct since GPS is one type of location technology that may or may not be used to acquire the user's location. Also GPS is also the name for the location system that makes use of satellites launched by the USA. There are other systems such as GLONASS (Globalnaya navigatsionnaya sputnikovaya sistema), Galileo, and so on (The Samsung Focus S supports both GPS and GLONASS).

Accuracy or Battery Friendly

Each one of these location technologies differs in the accuracy of the location that it provides. GPS is the most accurate with the margin of error being around 10 meters (32 feet) in favourable conditions. The next most precise location technology is WiFi based location. WiFi access points don't transmit nearly as far as cell towers. When you detect one you usually are literally within stone throwing distance of it. Cell tower based location is the least precise.

Generally speaking the more precise location technology (GPS) also has a more significant impact on battery life. When you need to acquire location information you can specify low or high accuracy mode. To preserve the user's battery life only request high accuracy information if you need it. If you only need a general location and don't expect your user to move around much during a session in your program it's a good idea to turn off location services after you've retrieved their location. Note: If you need the user's speed or elevation you will need to request a high accuracy location.

Once you have the user's location if you do not need to continually retrieve updated location information then turn off your location watcher. Doing so will power down the radios involved in retrieving the user's location and save battery life.

Getting Permission to Retrieve Location

Before retrieving the user's location you need to have permission to do so. There are two levels on which you'll need to retrieve location; on the device level and on the user level. On the user level it's just a matter of asking the user for permission to get their location. If precise location isn't absolutely needed then you may also want to give the user the option to select their location from a list of cities. You will also want to display a privacy notice to the user so that he or she knows how their location information will be used. There are some scenarios where you don't need to do this, but for now assume that this is always required. Retrieving the user location without getting permission and transmitting it over the Internet is a sure fire way to fail certification.

On the device level there are two things that you must do to have permission to use location services. You'll need to ensure that your application has requested the location services capability in the WMAppManifest.xml file. To do this ensure that you have the line <Capability Name="ID_CAP_LOCATION"/> in the <Capabilities/> section. Without this your application will not be able to make use of location services. Also note that the presence of this declarative capability request will also cause your application to be listed as an application that requires location services in the Marketplace.

Even though you've requested the location services capability a user can completely disable location services on their phone. I'll talk about how to deal with this in a moment.

What's in a Location

Location information is returned in the GeoCoordinate class. Let's take a look at the properties that class exposes

Member Type Description
IsUnknownboolIndicates whether or not the location object contains latitude/longitude data
LatitudedoubleUser's latitude
LongitudedoubleUser's longitude
HorizontalAccuracydoubleThe accuracy of the latitude and longitude in meters
AltitudedoubleUser's altitude in meters
VerticalAccuracydoubleAccuracy in meters
SpeeddoubleUser's speed in meter's per second

I listed IsUnknown first because if it is true then there's no use in looking at the other fields; they will contain no data of interest. I think that Latitude and Longitude explain themselves. The HorizontalAccuracy property tells you how far off the user's actual coordinates may be in meters while VerticalAccuracy tells how far off the altitude may be in meters. Those living in North America will want to take note that the Altitude and Speed properties user meters and meters per second. The Imperial measurement system is not being used here. If you need to display something in Imperial units remember to do a conversion first.

Getting the Location

Let's break away from discussing concepts and go through some code to retrieve the user's location. To retrieve the user's location you'll need to create a geocoordinate watcher, subscribe to a few events, and call it's Start() method.

C#
private GeoCoordinateWatcher _watcher = null;
public GeoCoordinate MostRecentPosition { get; set; }
	
void StartWatcher()
{
 if(_watcher == null)
  {
    _watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
    _watcher.PositionChanged += 
      new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
    _watcher.StatusChanged += 
      new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);
    } 
   _watcher.Start();
   if(_watcher.Permission == GeoPositionPermission.Denied)
   {
      //Location services is disable on the phone. Show a message to the user.
   }
}
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
   MostRecentPosition = e.Position.Location;
}
 void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
{

}

When the phone has more updated location information the PositionChanged event is fired. I'm placing the updated position in a property called MostRecentPosition and all subsequent code will work using the value in that property. Something to keep in mind is that Location Services operates on a thread separate from the UI thread. In many Windows based technologies (including Windows Phone and Silverlight) you cannot interact directly with UI elements from seconday threads. If you wanted to update a UI element it is necessary to use a Dispatcher to execute code back on the UI thread.

C#
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
   MostRecentPosition = e.Position.Location;
   this.Dispatcher.BeginInvoke(()=>
   {
      MyTextBox.Text = "Received a location!";
   }
}

Location Services Status

The geocoordinate watcher can have various status defined in the GeoPositionStatus enumeration. When the status changes the StatusChanged event is fired (also on a secondary thread).

GeoPositionStatus Enumeration
ValueMeaning
DisabledLocation services has been disabled
NoDataNone of the location providers have any location information
InitializingLocation services is still initializing (such as looking for GPS Satellite)
ReadyLocation services has data ready to be provided

Before Mango (Windows Phone 7.1) one would only expect the Disabled status if location services had been disabled before the program began to run; if it was available when the program started up then you would not need to check for it again during the life time of the program. Under Mango location services can become disabled at any time. While your program is running the user can press the Start button and go to settings (during which your program is still alive in the background) and then return to your program (waking it up) and location services will be disabled.

Formatting the Location Data

The members on the GeoCoordinate object that you get back that contain the latitude and longitude are of type double. You can format these fields the same way you would any other set of doubles. For example, lets say that you wanted to display the location with three figures past the decimal point. You could do it with the following.

string formatedLocation = String.Format("Lat/Long: {0:0.000},{1:0.000}",position.Latitude, position.Longitude);

Another way of displaying these numbers is using degrees, minutes, and seconds. As you might guess there is a relationship between these units and the units you might use to describe time on a clock. Every 24 hours the earth rotates 360 degrees (it's actually every 23 hours 56 minutes, but I won't get into the specifics of that). The amount that the earth rotates in one hour can be found by dividing 360 by 24. It is 15 degrees. So when some one mentions one hour of rotation that means the same as 15 degrees. There are 60 minutes in an hour. So how many degrees are in a minute of rotation? That can be found by dividing the 15 degrees of an hour of rotation by 60 which results in 0.25 degrees. To get degrees in a second of rotation divide the 0.25 degrees by 60. Given a rotational measurement you could use the following to perform the same steps to convert a measurement to degrees, minutes, seconds:

C#
public static string DegreesToDegreesMinutesSecondsString(double source)
{
    var d = Math.Floor(source);
    var remainder = (source - d) * 60;
    var m = Math.Floor(remainder);
    remainder = (remainder - m) * 60;
    var s = remainder;

    return String.Format("{0:0}° {1:00}' {2:00}\"", d, m, s);
}

Meeting Certification Requirements

When you are using location services there are a few things you must do to pass certification. Most importantly you must inform the user how you plan to use their location data. If the location data will never leave the device then let the user know this. If you need to call public web services with their location data but don't plan to transmit identifying information then let the user know this.

Your program must also be able to handle scenarios in which location services is disabled gracefully. Depending on the nature of your program you may be able to provide the user with a list of cities or allow the user to enter location information (such as a postal code) to manually set their location. If your program absolutely must have location services information (such as a speedometer application) then let the user know that the program needs location services is needed for operation.

Example Program

The application attached to this posting retrieves location information and displays it on the screen. It also will allow you to send a link to your location via e-mail and will show you how to to convert information retrieved to feet and miles per hour(for those that use the emperial system) and kilometers per hour. The program uses databinding to display information on the screen but I don't make much use of converters. Since the information can also be sent via e-mail I do formatting within code and both bind it to the screen and send it in an e-mail.

Things to Remember

  • Request the Location Services capability in your WMAppManifest.xml
  • Ask the user for permission to get their location
  • Be prepared for the possibility of location services being disabled on the phone
  • Don't transmit the user's location to any service without their permission
  • Only use high accuracy location when needed
  • Turn off location services when it is nolonger needed

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here