Geoposition advanced tracking scenarios for Windows Phone 8

This blog post was authored by Daniel Estrada Alva, a software development engineer on the Windows Phone team.

- Adam

Windows Phone 8 offers a new model for tracking a device’s position, based on change of distance, with the new Geolocator object. With this new model, the Geolocator object provides location updates at a defined time interval. This new functionality in Windows Phone 8 is different from tracking in Windows Phone 7, which uses an API that’s exposed through the MovementThreshold property to track device location.

The Geolocator object gives you more flexibility as you design your app by delegating most of the tracking logic to the Geolocator. Apps that require the acquisition of positions at a consistent time interval can now let the Geolocator handle the logic for them.

Choosing between ReportInterval and MovementThreshold

You can choose which model to use in your app to track a device’s position based on your needs. For example, if your app uses a very small movement threshold, the app could work better by defining a ReportInterval property.

Similarly, if the app defines a report interval to identify when the device moves a given distance or outside certain bounds, you should consider using the MovementThreshold property.

The following example illustrates how to use ReportInterval property:

Code Snippet
  1. public void StartTracking()
  2. {
  3.     if (this.trackingGeolocator!= null)
  4.     {
  5.         return;
  6.     }
  8.     this.trackingGeolocator = new Geolocator();
  9.     this.trackingGeolocator.ReportInterval = (uint)TimeSpan.FromSeconds(30).TotalMilliseconds;
  11.     if (this.positionChangedHandler != null)
  12.     {
  13.         this.positionChangedHandler = (geolocator, eventArgs) =>
  14.             {
  15.                 //…
  16.             };
  17.     }
  19.     // this implicitly starts the tracking operation
  20.     this.trackingGeolocator.PositionChanged += positionChangedHandler;
  21. }

Similarly, the following example illustrates how to use MovementThreshold property:

Code Snippet
  1. public void StartTracking()
  2. {
  3.     if (this.trackingGeolocator!= null)
  4.     {
  5.         return;
  6.     }
  8.     this.trackingGeolocator = new Geolocator();
  9.     this.trackingGeolocator.MovementThreshold = 100; // in meters
  11.     if (this.positionChangedHandler != null)
  12.     {
  13.         this.positionChangedHandler = (geolocator, eventArgs) =>
  14.             {
  15.                 // …
  16.             };
  18.         // this implicitly starts the tracking operation
  19.         this.trackingGeolocator.PositionChanged += positionChangedHandler;
  20.     }
  21. }

Please note that the Geolocator does not define a MovementThreshold or ReportInterval by default; both properties are set to zero. You must explicitly choose between these two properties by setting one of them.

If you don’t set either of the properties, the operation to set an event handler for either the PositionChanged event or the StatusChanged event will throw a first-chance exception that can be captured by the Visual Studio 2012 debugger. Rather than simply catching this exception, you should fix the problem. If your app takes these parameters from user input, please remember that setting the properties to zero is equivalent to leaving them “unset” and will result in an exception.

The MovementThreshold always takes precedence over ReportInterval. If both properties are set, the events will be triggered based on the MovementThreshold. The ReportInterval will be ignored.

Working with the tracking events

Two events provide position data and status feedback back to the app. The first event, PositionChanged, provides the most up-to-date Geoposition object that matches the requirements of the request. The second event, StatusChanged, provides the current status of the request. It’s important for an app that uses location-tracking sessions to subscribe to the StatusChanged event to identify error conditions.

Registering for both events is quite similar, and you can see examples in all the code snippets in this post.

The StatusChanged event provides the new status using the PositionStatus enumeration.

Note: The StatusChanged event is not available for single Geoposition requests.

Apps also can poll for current status through the LocationStatus property. You can use this alternative method, for example, to check whether the user turned the Location on or off, and whether to display a message or fall back to asking the user for their current location.

Request lifetime

The Geolocator uses an asynchronous pattern for tracking operations. However, it does not provide explicit methods in the interface to start and stop the tracking request. The Geolocator keeps track of the event handlers that are registered. It implicitly starts tracking when event handlers are registered, and stops when all event handlers have been unregistered.

The very first event handler that is registered with the Geolocator on either of the events (PositionChanged or StatusChanged) will start the tracking operation. Similarly, when the last event handler is removed (PositionChanged or StatusChanged), the Geolocator will stop the tracking operation.

With this model the app can concentrate on registering and unregistering event handlers when it needs notifications; it leaves the responsibility of managing the state of the operation to the Geolocator. On the other hand, it requires the app to be careful about when event handlers are registered and unregistered to avoid wasting power.

Registering the events should be deferred until the time notifications are needed. For example, apps should not register the event handlers on app load (if the notifications are not needed as soon as the app loads). Similarly, leaving event handlers registered when the app doesn’t need more notifications also wastes power.

Another important remark in this regard is that the Geolocator does not implement a dispose mechanism. Apps are expected to unregister all event handlers before they release the reference to the Geolocator.

The following code snippet shows how an app can use the event handlers correctly:

Code Snippet
  1. private Geolocator trackingGeolocator;
  2. private TypedEventHandler<Geolocator, PositionChangedEventArgs> positionChangedHandler;
  3. private TypedEventHandler<Geolocator, StatusChangedEventArgs> statusChangedHandler;
  5. public void StartTracking()
  6. {
  7.     if (this.trackingGeolocator!= null)
  8.     {
  9.         return;
  10.     }
  12.     this.trackingGeolocator = new Geolocator();
  13.     this.trackingGeolocator.ReportInterval = (uint)TimeSpan.FromSeconds(30).TotalMilliseconds;
  15.     if (this.positionChangedHandler != null)
  16.     {
  17.         this.positionChangedHandler = (geolocator, eventArgs) =>
  18.             {
  19.                 // …
  20.             };
  21.     }
  23.     if (this.statusChangedHandler != null)
  24.     {
  25.         this.statusChangedHandler = (geolocator, eventArgs) =>
  26.             {
  27.                 // …
  28.             };
  29.     }
  31.     // this implicitly starts the tracking operation
  32.     this.trackingGeolocator.StatusChanged += this.statusChangedHandler;
  33.     this.trackingGeolocator.PositionChanged += this.positionChangedHandler;
  34. }
  36. public void StopTracking()
  37. {
  38.     if (this.trackingGeolocator == null)
  39.     {
  40.         return;
  41.     }
  43.     this.trackingGeolocator.StatusChanged -= this.statusChangedHandler;
  44.     this.trackingGeolocator.PositionChanged -= this.positionChangedHandler;
  46.     this.trackingGeolocator = null;
  47. }

The app can’t change the DesiredAccuracy, or transition between MovementThreshold and ReportInterval while tracking is in progress. The Geolocator object can be reconfigured after all the event handlers are unregistered.

Error conditions

The Geolocator will always try to honor the DesiredAccuracy requested by the app within the limits of the technologies used internally. A “best effort” approach is used, so in some circumstances the accuracy of the position may be lower than what the app desires. Although this is simpler for single Geoposition requests, it’s worth a more detailed discussion for tracking operations with MovementThreshold or ReportInterval.

When a tracking request is first started, the platform may need some time to achieve the accuracy requested, and it will trigger multiple events with progressively increasing accuracies at a rate higher than ReportInterval. For example, during a “warmup” period for a request with a DesiredAccuracy of 50 meters and a ReportInterval of 30 seconds, the app could be notified more than once during the first 30 seconds, and will get Geopositions with a progressively increasing accuracy until the DesiredAccuracy is achieved. After that happens, the Geolocator will notify the app only when the information matches the parameters specified by MovementThreshold or ReportInterval.

A second case to consider is when the Geolocator temporarily loses the ability to acquire Geoposition information. This can happen when the device initiates a high-accuracy tracking session based on GPS, and subsequently enters a region where GPS can’t get a good satellite signal. Although the platform attempts to obtain position from other sources, there will be some periods of time when the position update rate is affected.

If the Geolocator entirely loses the ability to acquire Geoposition, it notifies the app of this error status. When the Geolocator enters an error condition, the app won’t receive Geoposition notifications until the Geolocator again starts to acquire data. This is another reason why it’s important for apps to register for status notifications; they can show appropriate UI during such error conditions.

When the Geolocator recovers from an error state, it sends the app a status notification with the new status. After this, the app can expect Geoposition notifications to start arriving again. Keep in mind that if the Geolocator was in an error state for a long time, there may be a “warmup” period as described previously in this post.

The following diagram describes the transition between various statuses for the Geolocator:


Note that when the Geolocator reaches the Ready state based on the PositionStatus enumeration, the app doesn’t send a status notification with the same state every time a Geoposition is available. The app only receives a status update when the status changes.

I hope you’ve found the information in this post useful, and that it will help you write great location-aware apps for Windows Phone 8.