Publications

Real World .NET, C#, and Silverlight

What’s New in Windows Phone 8 (6 out of 8)–Location services and maps

Windows Phone 8 brings long awaited updates to location services and brand new map control (with associated services) which is based on Nokia maps. Location services So what’s new in location services. First of all – the new WinRT API which is shared with Windows 8. To use location services application must declare the following capability in application manifest: <Capability Name="ID_CAP_LOCATION" /> The “main” class – Geolocator – belongs to Windows.Devices.Geolocation namespace and enables location tracking in good old “events” way and also new async model as follows: Geoposition currentPosition = await geoLocator.GetGeopositionAsync(); // or Geoposition currentPosition = await geoLocator.GetGeopositionAsync(TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(30)); Note: geoLocator is an instance of Geolocator object. Second call limits the results age and awaiting timeout. The object itself could be activated as follows: if (geoLocator == null) { geoLocator = new Windows.Devices.Geolocation.Geolocator(); geoLocator.DesiredAccuracy = Windows.Devices.Geolocation.PositionAccuracy.High; //Request high accuracy from GPS device geoLocator.DesiredAccuracyInMeters = 1; //Must have very precise for walking/running/biking...

Read More
Alex Golesh
MVP, MCPD, MCT
CTO, Sela USA
Alex Golesh, MVP, MCPD, MCT
CTO, Sela USA
Alex Golesh, MVP, MCPD, MCT  is an international expert in Windows Phone, Windows 8, Silverlight and WPF and serves as CTO at Sela USA. He is currently consulting in various enterprises in USA, Israel and worldwide, architecting and developing Smart Client and mobile solutions. Alex is known as one of the top Silverlight and Windows Phone experts worldwide.
What’s New in Windows Phone 8 (6 out of 8)–Location services and maps
Alex Golesh
MVP, MCPD, MCT CTO, Sela USA

Windows Phone 8 brings long awaited updates to location services and brand new map control (with associated services) which is based on Nokia maps.

Location services

So what’s new in location services. First of all – the new WinRT API which is shared with Windows 8. To use location services application must declare the following capability in application manifest:

<Capability Name="ID_CAP_LOCATION" />

The “main” class – Geolocator – belongs to Windows.Devices.Geolocation namespace and enables location tracking in good old “events” way and also new async model as follows:

Geoposition currentPosition = await geoLocator.GetGeopositionAsync();
// or
Geoposition currentPosition = await geoLocator.GetGeopositionAsync(TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(30));

Note: geoLocator is an instance of Geolocator object. Second call limits the results age and awaiting timeout.

The object itself could be activated as follows:

if (geoLocator == null)
{
    geoLocator = new Windows.Devices.Geolocation.Geolocator();
    geoLocator.DesiredAccuracy = Windows.Devices.Geolocation.PositionAccuracy.High; //Request high accuracy from GPS device
    geoLocator.DesiredAccuracyInMeters = 1; //Must have very precise for walking/running/biking tracking. Could use values of 50-100 for car
    geoLocator.ReportInterval = 1000; //1 second between updates usually is needed for constant updates for scenarios such as walking/running/biking tracking.
    geoLocator.StatusChanged += geoLoc_StatusChanged; //Subscribe for status changes
    geoLocator.PositionChanged += geoLoc_PositionChanged; //Subscribe for continues position changes updates
}

The PositionChanged result brings information such as CivicAddress, Coordinate information with Latitude, Longitude, Speed, Heading, Accuracy, Altitude, etc. fields which crucial for location-aware applications.

Sample code snippet for PositionChanged event:

if (position.CivicAddress != null)
    Debug.WriteLine(string.Format("City = {0}, Postal Code = {1}, State = {2}, Country = {3}",
                                  position.CivicAddress.City, 
                                  position.CivicAddress.PostalCode, 
                                  position.CivicAddress.State, 
                                  position.CivicAddress.Country));
 
Dispatcher.BeginInvoke(() =>
{
    txtLat.Text = position.Coordinate.Latitude.ToString();
    txtLon.Text = position.Coordinate.Longitude.ToString();
    txtSpeed.Text = position.Coordinate.Speed.HasValue ? position.Coordinate.Speed.ToString() : "UNKNOWN";
    txtHeading.Text = position.Coordinate.Heading.HasValue ? position.Coordinate.Heading.ToString() : "UNKNOWN";
});

Note: this sample code simply outputs the info on screen. While this change in API is interesting, the real power comes with ability to track the location when application is not active – works in background.

Background Execution

As you probably remember, on Windows Phone only one app runs in the foreground – the one which is visible on screen. When user navigates away from an app (either by pressing the Start button or by launching another app) the current app is suspended and may be terminated and tombstoned. In Windows Phone 8, a location-tracking app can continue to run in the background after the user navigates away, as long as the app continues to actively track location. This feature is absolutely must for scenarios such as an app that provides turn-by-turn directions. Let’s see how to enable the background execution.

First of all – to work in background the application must actively track the location: use Geolocator.

Also, to successfully use the Geolocator application must declare location capability (ID_CAP_LOCATION) as described above.

Next, application must require background execution in DefaultTask definition in application manifest as follows:

<DefaultTask Name="_default" NavigationPage="MainPage.xaml">
  <BackgroundExecution>
    <ExecutionType Name="LocationTracking" />
  </BackgroundExecution>
</DefaultTask>

Note: If more than one application requires background execution, only last one will be allowed to work in background. All previous/other “background executions” will be stopped.

Last, but not least, the application must handle RunningInBackground event which raised when location-tracking application transitions to background. When this event is raised, the application should stop all tasks that are not related to location tracking, including updates to the app’s UI. Subscribing to this even is done through App.xaml:

<shell:PhoneApplicationService
    Launching="Application_Launching" Closing="Application_Closing"
    Activated="Application_Activated" Deactivated="Application_Deactivated"
    RunningInBackground="PhoneApplicationService_RunningInBackground"/>

Handling the event in code:

public static bool isRunningInBackground = false;
 
private void PhoneApplicationService_RunningInBackground(object sender, RunningInBackgroundEventArgs e)
{
    isRunningInBackground = true;
 
    //Stop all unnecessary processes
}
 
private void Application_Activated(object sender, ActivatedEventArgs e)
{
    isRunningInBackground = false;
}

In my simple scenario, the location updates from background execution will be used to update application’s main tile:

FlipTileData ftd = new FlipTileData()
{
    Count = updatesCount,
    Title = "Position updated",
    BackTitle = position.Coordinate.Timestamp.ToLocalTime().ToString(),
    BackContent = string.Format("New position is LAT: {0}, LON: {1}",
                          position.Coordinate.Latitude,
                          position.Coordinate.Longitude),
    WideBackContent = string.Format("New position is LAT: {0}, LON: {1}. Moving with speed of {2} m/s with course of {3}°",
                          position.Coordinate.Latitude,
                          position.Coordinate.Longitude,
                          position.Coordinate.Speed.HasValue ? position.Coordinate.Speed.ToString() : "UNKNOWN",
                          position.Coordinate.Heading.HasValue ? position.Coordinate.Heading.ToString() : "UNKNOWN"),
};
 
mainTile.Update(ftd);

Those updates produces the following results:

imageimage

Note: please see the video at the end of this post to see the application working in background

Maps

In additional to great improvements to location services described above, Windows Phone 8 switches map component to Nokia maps. The new control could be found in Microsoft.Phone.Maps.Controls namespace (Microsoft.Phone.Maps assembly) and could be instantiated either from XAML or code behind. Sample XAML initialization:

<Controls:Map HorizontalAlignment="Center" VerticalAlignment="Center"
              Width="450" Height="400" x:Name="map"
              PedestrianFeaturesEnabled="True" LandmarksEnabled="True" ZoomLevel="17"/>

Note: the controls namespace defined in XAML’s header file as follows:

xmlns:Controls="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"

Once defined, the map’s properties could be also altered from code behind:

map.Pitch = 40;

Map supports different cartographic modes (Road, Hybrid, Areal, Terrain), color modes (Light, Dark), presenting landmarks/pedestrian features, pitch and rotation:

image

In addition, map supports multiple overlay layers which could be presented over map (car icon on image above) as follows:

BitmapImage bitmapImage = new BitmapImage(new Uri("/Images/car.png", UriKind.Relative));
Image img = new Image();
img.Source = bitmapImage;
 
mapOverlay = new MapOverlay();
mapOverlay.PositionOrigin = new Point(0.5, 0.5);
mapOverlay.Content = img;
mapOverlay.GeoCoordinate = map.Center;
 
MapLayer MyLayer = new MapLayer();
MyLayer.Add(mapOverlay);
map.Layers.Add(MyLayer);

Last, the map provides services, such as GeocodeQuery, ReverseGeocodeQuery and RouteQuery. Latter could be used to calculate (and display on ap) route between two given geo coordinates as follows:

RouteQuery routeQuery = new RouteQuery();
routeQuery.QueryCompleted += routeQuery_QueryCompleted;
 
void routeQuery_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
{
    Route theRoute = e.Result;
    MapRoute calculatedMapRoute = new MapRoute(theRoute);
    map.AddRoute(calculatedMapRoute);
}
 
private void btnShowRoute_Click(object sender, RoutedEventArgs e)
{
    if (!routeQuery.IsBusy)
    {
        List<GeoCoordinate> routeCoordinates = new List<GeoCoordinate>();
        routeCoordinates.Add(new GeoCoordinate(48.860339, 2.337599)); //Eiffel Tower coordinates
        routeCoordinates.Add(new GeoCoordinate(48.8583, 2.2945)); //Louvre coordinates
 
        routeQuery.Waypoints = routeCoordinates;
        routeQuery.QueryAsync();
 
        map.Center = new GeoCoordinate(48.8583, 2.2945); //Center map on first coordinates
    }
}

Clicking the “Show Route” button calculates the route and shows it on map:

image

The navigation instructions are also available and could be presented to user as follows:

//...
List<string> legsList = new List<string>();
foreach (RouteLeg leg in MyRoute.Legs)
{
   foreach (RouteManeuver routeManeuver in leg.Maneuvers)
   {
      legsList.Add(routeManeuver.InstructionText);
   }
}
 
//lstRouteList is a list showing the legs
lstRouteList.ItemsSource = legsList;

Working sample application video:

Sample location aware application

 

Next time I will blog about in-app-purchases (IAP) and new Windows.ApplicationModel.Store namespace shared with Windows 8.

 

Stay tuned,

Alex