22 November 2014

The Microsoft Band and me–three weeks later

Why? How?

I will be honest – I wasn’t really thinking the whole thing about wearables is more than a bit overhyped marketing stuff and that I personally would not get much use of it. Sure, you had all these devices that could track your running but I am not a really sporty person nor do I feel the need to tell the whole world where I was while I go running. Which is easy enough, because I don’t. So when I woke op on October 30th with the news the Microsoft Band had launched out of the blue, I was surprised but not really enticed by what I deemed to be ‘yet another fitness device’.

Boy, was I wrong.

My gadget addicted former colleague Jarno Peshier - who had read up on the specs - contacted me that morning, writing “I want one. You will be in the USA soon (for the MVP Summit). Let’s order two, you take them home, and split the next day delivery costs”. I was like, “what the heck, it’s not that expensive and if I don’t like it I can probably sell it off easily as they are not for sale in Europe”. So he ordered, got them delivered at the home of a friend living in Seattle, and before 3PM CET (while the USA was still kind of waking up) the order was already processed and two bands were on their way from California to Seattle. This quick decisive action turned out a be a very good idea indeed, as you all probably know what happened when the USA did wake up. Bands sold out faster than turkeys on Thanksgiving and back orders now stretch up until Christmas. MVPs arriving in Seattle mostly ran into sold-out stores. It must have been a pretty frustrating experience both for them and the ever friendly and helpful Store staff. But my Band was already delivered and waiting for me in Seattle a few hours before I actually got up to leave for the airport.

Notifications - the killer feature

Some 24 hours later I actually got my Band

and initially I thought it was pretty OK. At the very least, I could bug all the American MVPs who thought they could buy one in the Bellevue store which – of course – was cleaned out empty. After a few days, I noticed substantial changes in my behavioral patterns. Some week later, after I already was back home again, I found it was now an indispensible device. Why? One word – notifications. I was no longer attached to my phone. I even turned off my phone’s ringer and notification sounds. For a very simple reason. Consider someone like me, who is online a lot and has a Windows Phone. I get a notification. I pick up the phone. I look at the notification. But then I see all these other things on the screen. Which is the whole idea of Windows Phone – to be ‘glanceable’. But I tend get distracted by all these interesting things. So I go and answer this tweet, that Facebook post – and before I know 15 minutes have passed by, my wife – with whom I was on an the typical on-and-off talk when we both arrive home a bit tired from work, is now reading a book, whatever.

Now I get a light vibration on my wrist, look at the Band’s screen (I wear it face-up, so not like in the commercials or on the picture above, and it ended up on my right wrist for some reason), and can see enough if it’s important enough to get up and get my phone (that is lying around somewhere in the room, usually on the charging place) without missing a beat in a conversation. And you know what – usually it is not. I can see every notification from the Notification center, and every mail – but only the few first lines. The same during work. I don’t even have to lift my hands from the keyboard or mouse to check the notification. In a restaurant – my phone is somewhere in a pocket (or last time, in my wife’s handbag). At times, it’s more like a wireless hot spot for my Band ;)

Without noticing, I had become a more sociable creature, and more efficient too. The Band has become my gate keeper. Going into social media and mail is now a conscious decision. I have to get up and find my phone, for instance. Yet I don’t have to shut off my phone anymore to reach that state. I have found a kind of middle ground.

But there’s more

The calendar is synced to the Band as well, so even when I walk out of the house without my phone to do some quick shopping (I never forgot my phone before, but now I do) I still get calendar reminders. It has Cortana integration, so I can actually say “Remind me to take the pizza out of the oven in 30 minutes” to my Band using the action button, and it will remind me in 30 minutes. That will need connection to my phone at the moment I actually take the reminder, but I don’t need to get my phone first. And then I can get out of range and it will still remind me. The other day I was in bed, my wife was out, and my phone was lying around downstairs. I was very tired, and decided to tell my wife I went shut-eye. I found out I could actually say to my band “Text my wife I am going to sleep now” and sure enough, my phone, one floor down (and we have 40cm – well over a foot - concrete floors here) picked up the command. And it sent back response to my Band a minute later, too: “will be home in 15 minutes”.

And even more…

You can read online of course about all the that the Band does. It actually does quite a lot. Apart from notifications, alarms and the Cortana commands, it tracks hearth rate, steps, and calorie burn, you can use it as a fitness coach, track running (it has its own GPS so you don’t have to lug around your phone), and you can use it to check UV levels. I am not even sure I have the complete list covered now. I can tell you it felt a bit odd noticing that, when the cabin attendants told us to put all devices in airplane mode before taking off from Seattle, there is actually an airplane mode on the Band. In 2014, my freaking watch actually has airplane mode and takes voice commands. Welcome in the future.

I really think the UV meter is a really nice and smart touch in these days when we learn more and more about sun burn and skin cancer correlations. It basically takes a sample, and says how much minutes current sustained will typically get you a sunburn. As there has not been very much sun both in Seattle and here since I got the device, I only got “low” the few times the sun actually was out.

Some people, like Paul Thurrott, call it “Microsoft’s moonshot” meaning that Microsoft could not decide what should and should not go into it’s first wearable, so they put in everything and the kitchen sink, making the device complex and hard to operate. I personally think the day-to-day operation of the device is very easy (the tile interface is very simple and natural, especially for someone who has seen Windows Phone or Windows 8 applications) and there are only two buttons. How hard can it be. I think by putting all this stuff into one little device they actually made it something for everyone. My wife wants one too – not for all the gizmo’s I like, but for the fitness/sleep stuff.

Finally – what the designers probably never thought of as actual usage – it makes for an excellent night light in the dark. When you press the big button in the middle – even in sleep mode the screen gives off enough light to see a little by in the pitch dark. And since you are wearing it, you don’t have to find it first. Very useful when you are staying in a strange house or hotel and want to find the toilet without waking everyone up in the middle of the night by turning on the light (or crashing down the stairs – something I narrowly avoided last year).

Charge and charging

Your mileage may vary. The first day, you will probably have a very bad battery experience, as you constantly play with the device. Typical usage will last me just a little short of 48 hours. Charging from empty to full takes about 90 minutes I think, but the funny thing is – charging from like 30% to 80% (which will take you through the day) goes very fast, think 20 minutes (at most). So you can do that over breakfast or while you are in the shower. It only comes with a charging cable, any USB power port will do. Very nice, as it also saved me of having yet another useless USA plug charger ;)

Further effects so far

Apart from a different usage pattern for my phone, making me more sociable and efficient, it also has had an impact on my sleep pattern. I like the sleep tracker, but I don’t like what it’s telling me – I sleep too little. I thought I was getting 8 hours per night – it was more like a little over 6. I should rest more, and I do – it’s now close to 7 hours per night and already feel better. I also feel I will need to do more exercise, as the steps tracker has a default goal of 5000 steps and I get to that usually only half the time. In general, it makes me conscious about a lot of things I did not really know about.

Thoughts on improvements

So is this the perfect device? Not yet, although I must admit I like it 500% more than I ever imagined. My main concerns are

  • While the screen itself seems pretty scratch resistant, the actual watch housing very susceptible to scratching. That is probably why it comes with a free screen protector. I tried to apply that, it did not work out for me, and decided to pull it off again. So I wear the device face up and try to be careful. The housing is now somewhat scratched. As it it is black, it does not attract much attention IMHO. But in a V2 this could be improved upon
  • As the Band is now more or less functioning as a remote for my phone that is ‘somewhere’, I would much like a simple app or function to control the music player. Skip forward one track, skip back one track would be much appreciated. Skip forward 60 seconds, skip back 30 seconds would be an awesome bonus for listening to podcasts (and skipping ads).  I can do that with Cortana to an extent, but it does not always work, especially when the phone is streaming music over Bluetooth and thus that channel is already very busy.
  • I would like to be able to see a 2nd time on ‘Watch mode’. There’s room enough on the screen for that. As someone dealing a lot with people from another time zone (i.e. PST) that would be convenient.
  • The UV meter needs to take into account skin type, or just stick to saying the level. Apart from the level, it now says “typical times to sunburn nn minutes” but how does one define typical? Someone from African heritage can walk for hours in a sunshine that will burn a red-haired descendant from Irish stock into (blistering) misery in 15 minutes. That even varies over the year – while the first fierce spring sun can give bleached-out-me a sunburn, my skin darkens fairly quickly in the sun and the same level of sun power won’t bite me just a month later. I wonder if it would be possible to have the app take a picture of facial skin, analyze that and calibrate the sunburn time from that.
  • The design worries me a little. I find it pretty cool looking and comfortable to wear. It’s light and does not get in the way when I am working on a keyboard, which I found puzzling as my normal watch is too constrictive for wearing while typing. The Band is just a little bit flexible, light and does not get in the way. I also am a fussy sleeper (the most stupid things keep me awake), but I have no troubles sleeping with it. And yet - I have also noticed over the years that the rest of humanity does not necessarily agree with me on what is good looking and what is not. It only comes in black. I wonder how fashionists will think about it.
  • I understand why the companion app works and looks like it does. The New Microsoft went all-platform in the typical new way, which is very commendable and probably has contributed to the device selling out so fast. That does not help that on a Windows Phone it looks odd and alien. The awesome, well-designed and natural feeling UI of the Band itself is a stark contrast with the clunky UI of the companion app.
  • I want an SDK! I want an SDK! Please give me an SDK ;)

Conclusion

For a first launch into the wearables, Microsoft have done a tremendous job at a pretty compelling price. Even with expensive NDD I ended up a little north of €180 (yay Euro!). People routinely spend that on watches that look like they come out of the dashboard of the Titanic bridge - and those only display time. Going cross platform with it from the get go and making it available the next day – full marks. The first batch sold out in a day, the second – this week – lasted about 10 minutes. Consumer demand says it all. I find the device an invaluable companion device to my phone. Especially since I use a 1520, which is pretty big – I don’t pull it out half as much anymore these days. It’s the first gadget I bought that my wife is very explicitly happy about, because I am less distracted. She wants to have one too – that is going to be a bit of a challenge I think. I am also very happy with it, to the extent that I would to get another one ASAP if this one would break down. In the mean time, I just have to be careful.

Long story short – if you are interested in these kind of devices and recognize this user story (or even partially) – go and try to get one. You won’t regret it and even on the very off chance you will – plenty of takers. ;)

Disclaimer

I am not a professional reviewer. This is just my experience with this one device, after about 3 weeks. As I have no comparison material, I also cannot tell if this device is better than comparable devices. I just felt the need to write it from a tech user’s perspective.

12 November 2014

Executing and testing geofencing background tasks in Universal Apps

Intro

On October 18th the Dutch and Belgian Windows Platform Development communities got together for an event called “Lowlands WPdev 2014”- yours truly was one of the conference organizers, and gave a talk about geofencing. This blog post is basically a partial write-down, just explaining the code and how to test it.

The ShopAlerter application

The application is very simple and shows itself like this on Windows Phone 8.1 and Windows 8.1:

imageimage

It shows the created geofences on the map. On Windows Phone, we use Here Maps, on Windows we use Bing Maps. As both banners show, you should get a key for both map platforms to get you app certified. As the enters a geofence, a trigger is fired to show you are approaching a shop and a toast message is being displayed. That is – in theory. In practice stuff is not so easy, especially in Windows.

Project structure

image

The project consists out of what nowadays is a pretty standard Universal App structure, with a Windows, Windows Phone and a Shared Project. In the shared project is the App.xaml and a partial class MainPage.cs, basically holding some of the code behind stuff that normally goes into MainPage.xaml.cs. But we want to share as much code as possible – and we can.

The Mapping.Utilities.Pcl contains helper methods to visualize geofences on the map – described in an earlier article about visualizing geofences.

The MappingUtilities.Windows contains one helper class to convert to the common Geopoint type to the specific Location and LocationCollection types used by Bing Maps.

Finally, the ShopAlerter.Background is a so-called Windows Runtime Component. Background tasks need to be defined specifically in such a component. I am not entirely sure why, but that’s the way it is.

Windows Phone project

The Windows Phone project is pretty simple: a little bit of XAML, and some code behind. The XAML is just this:

<Page[Name space stuff omitted]>
  <Page.BottomAppBar>
    <CommandBar>
      <AppBarButton Icon="ZoomOut" Label="zoom out" Click="ZoomOut"/>
      <AppBarButton Label="Geofences" Icon="View" Click="ToggleGeofences"/>
      <AppBarButton Label="Task" Icon="Target" Click="ToggleTask"/>
    </CommandBar>
  </Page.BottomAppBar>

  <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid Margin="12,0,12,0" >
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
      </Grid.RowDefinitions>
      <StackPanel Margin="0,0,0,5">
        <TextBlock TextWrapping="Wrap" Text="ShopAlerter" FontSize="26.667"/>
      </StackPanel>
      <maps:MapControl Grid.Row="1" x:Name="MyMap" >
      </maps:MapControl>
    </Grid>
  </Grid>
</Page>

A command bar with three buttons, and a grid containing the header text and the map itself. The user hits the middle geofences button to turn the geofences on and off, and hits the right button to register the task. The left(zoom out) button is only there for demo purposes – believe me, sometimes the touch screen and the emulator suddenly decide no longer to play together, and while zooming in with a mouse is easy (just double click), zooming out is not possible. So although I don’t consider myself a pro presenter, I feel I can give pro tip here for demoing something with maps – always include a zoom out button to save your … behind when something goes wrong ;-)

It’s hard to believe, but the Windows Phone specific code, in MainPage.Xaml.cs is just this:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
  GeofenceMonitor.Current.Geofences.Clear();
  MyMap.Center = new Geopoint(
    new BasicGeoposition { Latitude = 52.155915, Longitude = 5.390376 });
  MyMap.ZoomLevel = 16;
}

const int fenceIndex = 1;
private void DrawGeofences()
{
  //Draw semi transparent purple circles for every fence
  var color = Colors.Purple;
  color.A = 80;

  // Note GetFenceGeometries is a custom extension method
  foreach (var pointlist in GeofenceMonitor.Current.GetFenceGeometries())
  {
    var shape = new MapPolygon
    {
      FillColor = color,
      StrokeColor = color,
      Path = new Geopath(pointlist.Select(p => p.Position)),
      ZIndex = fenceIndex

    };
    MyMap.MapElements.Add(shape);
  }
}

private void RemoveGeofences()
{
  var routeFences = MyMap.MapElements.Where(
      p => p.ZIndex == fenceIndex).ToList();
  foreach (var fence in routeFences)
  {
    MyMap.MapElements.Remove(fence);
  }
}

This is the power of the Universal App. All the rest is either in the shared project or the Windows Runtime Component that is also used both on Windows and Windows Phone. What you basically see is the OnNavigatedTo method that clears the geofences, and sets the zoom level and center point of the map. The other two methods are just used for drawing circles on the map and removing them – also showed in the same article I wrote earlier in my article about visualizing geofences.

The Shared project

So what's in this famous shared project then, huh? Well, just the partial class MainPage.cs. This adds methods to both the Windows and the Windows Phone MainPage.xaml.cs. The key thing is to understand code is shared, not binaries. Every line is compiled twice, both into the Windows and the Windows Phone project. Unlike Portable Class Libraries or Windows Runtime Components, which are shared binary.

So. The method called by pressing the middle button adds (and shows) or removes the geofences. This is a simple toggle function like this.

private void ToggleGeofences(object sender, RoutedEventArgs e)
{
  if (!GeofenceMonitor.Current.Geofences.Any())
  {
    foreach (var location in LocationObject.GetLocationObjects())
    {
      AddFence(location.Id, location.Location);
    }

    DrawGeofences(); // Actual implementation deferred to none shared portion
  }
  else
  {
    GeofenceMonitor.Current.Geofences.Clear();
    RemoveGeofences(); // Actual implementation deferred to none shared portion
  }
}

Note the actual drawing and removing is done by none shared code. This implies that both in Windows and in Windows Phone there must be methods "DrawGeofences" and "RemoveGeofences" implemented. You can also see here a method "AddFence" being called. This creates an actual geofence that is being monitored by the device:

  public void AddFence(string key, Geopoint position)
  {
    // Replace if it already exists for this key
    var oldFence = GeofenceMonitor.Current.Geofences.FirstOrDefault(p => p.Id == key);
    if (oldFence != null)
    {
      GeofenceMonitor.Current.Geofences.Remove(oldFence);
    }

    var geocircle = new Geocircle(position.Position, 150);
    const bool singleUse = false;
    MonitoredGeofenceStates mask = 0;
    mask |= MonitoredGeofenceStates.Entered;

    // NOTE: Dwelling time!
    var geofence = new Geofence(key, geocircle, mask, singleUse, 
                                TimeSpan.FromSeconds(1));
    GeofenceMonitor.Current.Geofences.Add(geofence);
}

The key thing about geofences is that they, well, have a key as well as a location. So if you add a geofence, you should first check if a geofence with the given key is already present. If it is, delete it first before adding one with the same key.

Then I create the shape for the geofence. Currently, only circles are supported so I create a circle with 150 meters in diameter. Then I define the geofence should be used multiple times – setting singleUse to true will make it disappear from the GeofenceMonitor automatically after it has been triggered. The mask will determine to what events the GeofenceMonitor will respond on this particular geofence. You can choose between Entered, Exited, Removed and None – to respond to multiple events, just OR ( +| ) to the mask like I show in the code.

Finally a word on dwelling time. This feature is here to prevent edge cases, in the most literal sense of the word. Suppose you are sitting on the edge of a fence – geo positioning is never that accurate, and the phone would probably detect it’s in, out, in, out, in (etc) the fence. If your App user gets a bazillion notifications showing that, you will probably not hit a 5 star rating anytime soon. So the default value is 10 seconds – only if you are 10 seconds in a geofence (or left it for 10 seconds) something will happen. For my demos I usually take 1 second because well, audiences tend to get uncomfortable watching a screen where nothing much happens (and the presenter too, for what matters). For production scenario’s, take some time to think about the speed your typical user will move with, the size of your geofences, and the dwelling time you select. I spent some time figuring out why none of my triggers ever went off – using the default 10 seconds, geofences with a 25 m diameter, and moving at 50km/h. I was already out of any fence again before even half the dwelling time had passed ;-)

Finally the method to register the background task, which is pretty simple:

private async void ToggleTask(object sender, RoutedEventArgs e)
{
  var registered = AlertTask.IsTaskRegistered();
  if (registered)
  {
     AlertTask.Unregister();
  }
  else
  {
    await AlertTask.Register();
  }

  var dlg = new MessageDialog(
     string.Format("Task {0}", !registered ? "registered" : "unregistered"));
  await dlg.ShowAsync();
}

The Background task

The background task is defined in one class containing the actual implementation of the task, as well as some static methods to handle registering and unregistering – an idea from our local DX guru Rajen Kishna, that I improved a little upon. The basic class definition with the required Run method is pretty simple:

public sealed class AlertTask : IBackgroundTask
{
  public void Run(IBackgroundTaskInstance taskInstance)
  {
    var monitor = GeofenceMonitor.Current;
    if (monitor.Geofences.Any())
    {
      var reports = monitor.ReadReports();
      foreach (var report in reports)
      {
        var l = LocationObject.GetLocationObject(report.Geofence.Id);

        switch (report.NewState)
        {
          case GeofenceState.Entered:
            {
              ShowToast("Approaching shop", l.Name);
              break;
            }
        }
      }
    }
  }
}

Mind you – in a Windows Runtime Component classes are sealed. This is mandatory. Anyway, when the background task is triggered, I first check if there are any geofences – logically there should be, for what else could have triggered this task. But they have been deleted on some other thread – it never hurts to be careful. Then I follow this procedure:

  1. Read all the reports from the monitor
  2. Each report should hold a Geofence object
  3. That has an id
  4. Use the id to retrieve the original object the geofence was created from

For the last step I use a LocationObject helper method. That is kind of my ‘data base’, which I will show later. Having retrieved the object, I can show it’s name in a toast.

private static void ShowToast(string firstLine, string secondLine)
{
  var toastXmlContent = 
    ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);

  var txtNodes = toastXmlContent.GetElementsByTagName("text");
  txtNodes[0].AppendChild(toastXmlContent.CreateTextNode(firstLine));
  txtNodes[1].AppendChild(toastXmlContent.CreateTextNode(secondLine));

  var toast = new ToastNotification(toastXmlContent);
  var toastNotifier = ToastNotificationManager.CreateToastNotifier();
  toastNotifier.Show(toast);

  Debug.WriteLine("Toast: {0} {1}", firstLine, secondLine);
}

A simple helper method, that I kinda stole from Rajen as well. My only improvement is the Debug.WriteLine at the end, which we unfortunately will need badly further down the road.

The methods to query the background task’s state, to register and unregister is are also based upon Rajen’s sample, only I have made the Register task actually awaitable. That’s a real live application of the trick I blogged about yesterday.

private const string TaskName = "ShopAlerterTask";
//NOTE:  WinRT component cannot return a Task<T>, but CAN return 
//IAsyncOperation<T>/>
public static IAsyncOperation<bool> Register()
{
  return RegisterInternal().AsAsyncOperation();
}

private async static Task<bool> RegisterInternal()
{
  if (!IsTaskRegistered())
  {
    await BackgroundExecutionManager.RequestAccessAsync();
    var builder = new BackgroundTaskBuilder 
      { Name = TaskName, TaskEntryPoint = typeof(AlertTask).FullName };

    builder.SetTrigger(new LocationTrigger(LocationTriggerType.Geofence));
    builder.Register();
    return true;
  }
  return false;
}

public static void Unregister()
{
  var entry = BackgroundTaskRegistration.AllTasks.FirstOrDefault(
     t => t.Value.Name == TaskName);

  if (entry.Value != null)
  {
    entry.Value.Unregister(true);
  }
}

public static bool IsTaskRegistered()
{
  return BackgroundTaskRegistration.AllTasks.Any(t => t.Value.Name == TaskName);
}

In the RegisterInternal method I simply make a fairly standard background task, only it’s now triggered by a LocationTrigger. The odd thing is, the only parameter you can – and must – supply to the LocationTrigger’s constructor is a LocationTriggerType enum, and that only has one value – Geofence. I assume the API designers originally planned to implement more options here but in it’s current state it’s looking a bit strange. But anyway, it works, that’s the important part. If now anyone enters or exits a geofence, the Run method will be called.

Location object

This is not very interesting, but only showed here for the sake of completeness. It’s basically an object with an ID and a location (which I need for creating a geofence) and a name to display. Two static helper methods help me to create a list of fake hard coded objects, or retrieve one by ID. The area is real – it’s the main shopping street of my home town Amersfoort – but the data is completely fake. There is, unfortunately, no Microsoft store on this continent, let alone in Amersfoort.

public sealed class LocationObject
{
  public LocationObject()
  {
  }

  public LocationObject(string id, string name, 
     double latitude, double longitude)
  {
    Id = id;
    Name = name;
    Location = new Geopoint(
        new BasicGeoposition 
          { Latitude = latitude, Longitude = longitude });
  }

  public string Id { get; set; }

  public string Name { get; set; }

  public Geopoint Location { get; set; }

  public static IEnumerable<LocationObject> GetLocationObjects()
  {
    return new List<LocationObject>
           {
             new LocationObject("1","Microsoft Store", 52.157043, 5.392407),
             new LocationObject("5","Colruyt", 52.156339, 5.391015),
             new LocationObject("9","The PhoneHouse", 52.154651, 5.388553),

           };
  }
  public static LocationObject GetLocationObject(string id)
  {
    return GetLocationObjects().FirstOrDefault(p => p.Id == id);
  }
}

Testing the Windows Phone project

This is pretty easy, thanks to the awesome Windows Phone emulator and it’s tools. Deploy the Windows Phone 8.1 project to the emulator, then proceed as follows (I kind of like that Bothell is displayed by default, as I spend two nights there recently visiting an old friend):

image

  1. imagePress the “Additional tools” button
  2. Select the “Location” tab
  3. Select the “Load” button
  4. Find the file “Locations.xml” that comes with the demo solution (it is in the project root) and select it.

Note I also marked the play button – we will need that later. After you have loaded the xml file, zoom in about five times (press the zoom in button) and you should see about as displayed on the right.

Then proceed as follows:

  • Press the middle button on the application bar (the one that is labeled “Geofences”). The geofences should appear as semi translucent circles as displayed in the very first image on top of this post.
  • Then press the right button on the application bar (“Task”) – this should pop up a message box indicating the task has been registered
  • The press the “Play” button on the Location Tools

Now if you have done everything right, pretty soon you should see the first toast pop up, and they should appear in the notification center as well. Since the phone should move on walking speed (it’s a pedestrian area) you might need to wait for a while for them all to appear.

imageimage

Awesome. Now it’s time to have a look at the Windows project.

The Windows project

Since we are using maps we are actually in a quite bad position, as the convergence story is still pretty weak in this area. For Windows uses Bing Maps – you will need to install the Bing Maps toolkit, use a different kind type of object for map positions (Location in stead of Geopoint), and Bing Maps is a native component so this will make your app a native app, too (i.e. not AnyCPU). And yet… This is all the XAML we need

<Page>
  <Page.BottomAppBar>
    <CommandBar IsOpen="True">
      <CommandBar.SecondaryCommands>
        <AppBarButton Icon="ZoomOut" Label="zoom out" Click="ZoomOut"/>
      </CommandBar.SecondaryCommands>
      <AppBarButton Label="Geofences" Icon="View" Click="ToggleGeofences"/>
      <AppBarButton Label="Task" Icon="Target" Click="ToggleTask"/>
    </CommandBar>
  </Page.BottomAppBar>
  <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <maps:Map x:Name="MyMap"></maps:Map>
    <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="ShopAlerter" 
               VerticalAlignment="Top" Foreground="Black" FontSize="48"
               Margin="150,5,0,0"/>
  </Grid>
</Page>

Granted, different, but not that different and I also choose a little bit different layout anyway. The only Windows specific code is this:

 MapShapeLayer fenceLayer;

protected override void OnNavigatedTo(NavigationEventArgs e)
{
  base.OnNavigatedTo(e);
  GeofenceMonitor.Current.Geofences.Clear();

  MyMap.Center = 
  new Location { Latitude = 52.155915, Longitude = 5.390376 };
  MyMap.ZoomLevel = 17;

  fenceLayer = new MapShapeLayer { ZIndex = 1 };
  MyMap.ShapeLayers.Add(fenceLayer);
}

private void DrawGeofences()
{
  var color = Colors.Purple;
  color.A = 80;
  foreach (var pointlist in GeofenceMonitor.Current.GetFenceGeometries())
  {
    var shape = new MapPolygon
    {
      FillColor = color,
      Locations = pointlist.ToLocationCollection()
    };
    fenceLayer.Shapes.Add(shape);
  }
}

private void RemoveGeofences()
{
  fenceLayer.Shapes.Clear();
}

That is all.  I love the Universal App model. All I need are methods to set the initial zoom level and location of the map, and methods to draw and delete geofence geometries. The rest is shared code in some way or the other.

You can see here Bing Maps uses the concept of layers. That’s about the only thing Bing Maps handles better than Here Maps IMHO – the z-index of map objects is handled by a layer object rather than on a per-object basis. This makes certain display manipulations a lot easier and faster. The real pain, though, is in testing this.

Testing the Windows project

We will need to test in the Windows Simulator. After all, we will need to test using locations, and I don’t feel like running around our main shopping street testing my app. Now there are some interesting challenges:

  1. The Simulator does not support a notion of route – only of location. You can basically appear on one location and then on another, but not make it smoothly move from a to b, like the Windows Phone simulator. But that is the least of our worries.
  2. The Windows simulator does not display toast notifications. This apparently has something to do with the simulator being a kind-of-copy of your actual PC, with all your apps installed.
  3. The Windows simulator does not allow the registration of background tasks. Try it. You will simply get an exception saying “This request not supported”. You can unregister, but not register. I have no idea why.

This sounds like a classical catch-22 – we need the Simulator to simulate locations, but we cannot register background task to actually use those locations, and even if we could, we cannot display the result. But there is a way out. Kind of. A long and winding way. Follow these steps:

  1. Run the app from Visual Studio on your local machine first.
  2. Make sure the “Debug Location” toolbar is visible. If it’s not: click View/Toolbars and check “Debug Location”. You will need to do this step only once.
  3. Press the “Task” Application bar button. This will show the following pop up, that you may have seen before on other apps asking for background access
    image
    and if you press “Allow” you will get
    image
  4. The task is now registered. Now stop the application (just from Visual Studio).
  5. Deploy and run the app from Visual Studio on the simulator. Remember I wrote about this being a kind of copy of your PC? Guess what, your app is already there, including the background task.
  6. Hit the “Geofence” application bar button. You will now see the geofences.
  7. You will now have to set the location of the simulator. There’s a button for that on the right hand side of it’s window. I picked the location of the ‘Microsoft Store’ as location.image
  8. Nothing happens if you press the “Set Location” button. Now go to the Debug/Location toolbar. Click the Lifecyle Events drop down. It should show the following, if it does not, try to reselect the
    ShopAlerter.Windows.exe again first
    image
  9. Still nothing seems to happen. But if you mosey back to Visual Studio and have a look at your output window….
    image
    Lo and behold – the result of the Debug.WriteLine. The toast code has fired, the geofence therefore has been activated, thus our code works.

Some thoughts and things to take into account

  • To make this app work at all, you will need to set some capabilities. For both apps, you will need the “Location” capabilities, and both applications needs to be Toast capable.
  • For the Windows application, you will need to set a Badge logo.
  • To save battery and to prevent you app from hogging the processor, LocationTriggers will only fire once every 2 minutes – at most, at least on the phone. So this technique is not very suitable for high-precision, high-speed tracking. Geofence events will “coalesce”, as it is so beautifully called – meaning they happen about every two minutes all at the same time.
  • The Windows Simulator – to put it very mildly – is not quite on par with the Windows Phone emulator. Particularly the situation around location simulation, background tasks and notifications could benefit significantly from quite some attention. I sincerely hope this will be addressed in some future release – preferably the very next one.

Credits

I have been standing on the shoulders of giants cobbling this all together, most notably:

Demo solution available here.

11 November 2014

Returning Task<T> from a Windows Runtime Component

A very short tip this time, that took me some time to find out.

You will need a Windows Runtime Component if you want, for instance, host a background task in an Universal App. The problem with these components is that you cannot return a Task<T> from a public method. You can use Task<T> inside the component, but not return it to the outside world. If you have a method

public async Task<bool> SomeMethod()
{
  return false; // whatever
}

in your Windows RT component, it won’t even compile. But there is a solution – you can return an IAsyncOperation<T>, and that is awaitable too.

Therefore, I use this simple wrapper to use the method both from inside and outside:

public IAsyncOperation<bool> PublicMethod()
{
  return InternalMethod().AsAsyncOperation();
}

private Task<bool> InternalMethod()
{
  return false; // whatever
}

And we’re done. This will compile, and you can now call “await myObject.PublicMethod()” from outside the Windows Runtime Component.

Sometimes code is so easy if you just know how to do it. No sample this time (again) as this is such a small piece of code. If you want to see it running, wait for the next post ;)