IT tutorials
 
Mobile
 

Windows Phone 8 : Building Location Aware Apps - Getting Started with Location (part 3) - Code-Driven Location Simulation

1/27/2015 3:08:19 AM
- How To Install Windows Server 2012 On VirtualBox
- How To Bypass Torrent Connection Blocking By Your ISP
- How To Install Actual Facebook App On Kindle Fire

Code-Driven Location Simulation

The Windows Phone emulator’s location simulator is useful for testing your app while it is executing within the emulator. To test the geo location features of your app on a physical device or within a unit test requires a different code-driven approach.

This section demonstrates how to abstract the use of the Geolocator class so that it can be replaced by a testable mock class.

On first glance you might think that mocking the SDK’s geo location API should be a simple affair. Many of the classes in the API are, however, sealed—including the Geolocator class. This makes mocking them awkward because they must be wrapped or accessed via custom proxy classes.

The Geolocator class implements an internal IGeolocator interface, which would make an excellent candidate for abstracting the duties of the Geolocator class. Unfortunately, IGeolocator is marked internal, putting it out of our reach.

So the downloadable sample code includes a custom IGeoLocator interface, which is almost identical to the SDK’s IGeolocator interface (see Listing 2).

LISTING 2. IGeoLocator Interface


public interface IGeoLocator
{
    event EventHandler<PositionChangedProxyEventArgs> PositionChanged;
    event EventHandler<StatusChangedProxyEventArgs> StatusChanged;

    Task<GeopositionWrapper> GetGeoCoordinateAsync();

    Task<GeopositionWrapper> GetGeoCoordinateAsync(
        TimeSpan maximumAge, TimeSpan timeout);

    PositionAccuracy DesiredAccuracy { get; set; }
    PositionStatus LocationStatus { get; }
    double MovementThreshold { get; set; }
    uint ReportInterval { get; set; }

    void Start();
    void Stop();
}


A custom GeolocatorProxy class wraps the built-in Geolocator object. GeolocatorProxy implements the IGeoLocator interface (see Listing 3). GeolocatorProxy is designed to be used in place of the Geolocator class. It offers all the features of the built-in Geolocator, but can be swapped out during testing.

Although the built-in Geolocator class does not include methods for starting and stopping location tracking, implementations of the custom IGeoLocator interface do. GeolocatorProxy subscribes to its Geolocator events in the Start method and unsubscribes in the Stop method.

The PositionChanged and StatusChanged events of the built-in Geolocator class use a TypedEventHandler<T> as the delegate type rather than the familiar EventHandler. The appearance of the TypedEventHandler is new to the Windows Phone 8 SDK and several APIs, including the geo location API, make use of it. This proves troublesome when working with Reactive Extensions (Rx). Thus, the GeolocatorProxy exposes the events using the nongeneric EventHandler class.

One last obstacle to abstracting the geo location API is that some of the types in the SDK’s geo location API do not provide the means for setting their members. These classes include, in particular, the PositionChangedEventArgs, StatusChangedEventArgs, and the Geoposition classes, which have been replaced with more flexible custom types to accommodate our mocking framework.

LISTING 3. GeolocatorProxy Class (Excerpt)


public sealed class GeolocatorProxy : IGeoLocator
{
    readonly Geolocator geolocator = new Geolocator();
...
    public uint ReportInterval
    {
        get
        {
            return geolocator.ReportInterval;
        }
        set
        {
            geolocator.ReportInterval = value;
        }
    }

    public void Start()
    {
        Stop();

        geolocator.PositionChanged += HandlePositionChanged;
        geolocator.StatusChanged += HandleStatusChanged;
    }

    public void Stop()
    {
        geolocator.PositionChanged -= HandlePositionChanged;
        geolocator.StatusChanged -= HandleStatusChanged;
    }

    public event EventHandler<PositionChangedProxyEventArgs> PositionChanged;

    void OnPositionChanged(PositionChangedProxyEventArgs e)
    {
        PositionChanged.Raise(this, e);
    }

    void HandlePositionChanged(Geolocator sender, PositionChangedEventArgs args)
    {
        OnPositionChanged(new PositionChangedProxyEventArgs(
                        new GeopositionWrapper(args.Position)));
    }
...
}


The custom MockGeoLocator mimics the behavior of the built-in Geolocator and allows you to supply a list of GeoCoordinate values that represent a predefined route and are analogous to the location simulator’s map points.

In addition to the properties of the IGeoLocator interface, MockGeoLocator has the following three properties that allow you to tailor when the PositionChanged event is raised:

- InitializationMsThe time, in milliseconds, before transitioning the Status to the NoData state

- FixDelayMsThe time before the transitioning the Status from the NoData state to the Ready state

- PositionChangedDelayMsThe time interval, in milliseconds, between PositionChanged events

MockGeoLocator allows you to add waypoints to a list of GeoCoordinate values using its WayPoints property.

The MockGeoLocator.WalkPath method runs on a background thread and processes the waypoints sequentially (see Listing 4).

If there are no waypoints specified, the MockGeoLocator uses a default list of coordinates.

The first time WalkPath is called, the class simulates initialization by pausing for the duration specified by the InitializationMs value. It then updates its Status to Ready and iterates over the WayPoints collection, raising the PositionChanged event for each one.

LISTING 4. MockGeoLocator.WalkPath Method


void WalkPath()
{
    if (wayPoints.Count < 1)
    {
        List<GeoCoordinate> defaultWayPoints = GetDefaultCoordinates();
        wayPoints.AddRange(defaultWayPoints);
    }

    if (firstRun)
    {
        Status = PositionStatus.Initializing;
        Wait(InitializationMs);
    }

    Status = PositionStatus.NoData;
    Wait(FixDelayMs);

    GeoCoordinate coordinate = wayPoints.First();

    if (firstRun)
    {
        Position = new Position<GeoCoordinate>(
                            DateTimeOffset.Now, coordinate);
        firstRun = false;
    }
    Status = PositionStatus.Ready;
    Wait(PositionChangeDelayMs);
    int index = 1;

    while (started)
    {
        if (wayPoints != null && wayPoints.Count > index)
        {
            coordinate = wayPoints[index++];
        }
        SetPosition(coordinate);
        Wait(PositionChangeDelayMs);
    }
}


The Wait method uses the Monitor to block the background thread for the specified number of milliseconds (see Listing 5).


Tip

Using the Monitor to block the thread is preferable to calling Thread.Sleep because, unlike Monitor.Wait, Thread.Sleep cannot be unblocked.


LISTING 5. Wait Method


static readonly object waitLock = new object();

static void Wait(int delayMs)
{
    if (delayMs > 0)
    {
        lock (waitLock)
        {
            Monitor.Wait(waitLock, delayMs);
        }
    }
}


Both MockGeoLocator and the GeolocatorProxy implement IGeoLocator. This allows you to use either type without referring to a concrete implementation, which is demonstrated in the next section.

 
Others
 
- Windows Phone 8 : Building Location Aware Apps - Getting Started with Location (part 2) - Background Location Tracking
- Windows Phone 8 : Building Location Aware Apps - Getting Started with Location (part 1) - Geolocator Class
- Windows Phone 8 : Building Location Aware Apps - Location Sensing Technologies
- Windows Phone 8 : Range Controls (part 2) - Progress Indicator, Slider , ScrollBar
- Windows Phone 8 : Range Controls (part 1) - ProgressBar
- Windows Phone 8 : Items Controls - ListBox, ComboBox
- Windows Phone 8 : LinkedIn (part 3) - Posting a Message, The Feeds Filter
- Windows Phone 8 : LinkedIn (part 2) - Accessing LinkedIn Content, Responding to a LinkedIn Post
- Windows Phone 8 : LinkedIn (part 1) - Configuring Your LinkedIn Account
- Windows Phone 8 : Twitter (part 2) - Checking for Tweets, Responding to a Tweet, Checking Twitter Notifications
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
programming4us programming4us
 
Popular tags
 
Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8 BlackBerry Android Ipad Iphone iOS