Developing For Microsoft Band With WinRT - Background Execution

In this article, I'm going to cover the basics of getting your Band connected using a Background Task in a Windows Phone application.

If you've not yet discovered the basics of working with the Band SDK, check out my previous articles in this "Developing for Microsoft Band with WinRT" series. You'll need some experience to understand what I'm covering and how you can extend it to fit your needs.

Setup the background task

To get yourselves started with background execution, you'll need to add a new project to your solution that will be solely for your background task class. You'll need to create a new Windows Runtime Component, not a Portable Class Library.

You will then need to create a sealed class within this project that inherits from the IBackgroundTask interface in the Windows.ApplicationModel.Background namespace. You'll then need to add the interfaces only method, Run, that as indicated by the method name, runs when the background tasks are executing. It will provide you with a parameter that you can access a deferral from. You'll need to do this if you're going to be using your background task to access the data from the sensors.

The basic layout for this Run method will look like the following:

  1. public async void Run(IBackgroundTaskInstance taskInstance)  
  2. {  
  3.     this._deferral = taskInstance.GetDeferral();  
  4.   
  5.     // ToDo: Possibly check the cost of performing the BG task on the device. If high, then don't perform the task?  
  6.   
  7.     try  
  8.     {  
  9.         // ToDo: Connect to the band and get the data  
  10.     }  
  11.     catch (Exception)  
  12.     {  
  13.         // ToDo: Complete the deferral and disconnect from the band  
  14.     }  
  15. }  
As you can see from this basic layout, we're getting the deferral from the task instance and holding it so we can complete it later. This will keep the background task alive and not drop out before we've done what we need it to do.

Getting Microsoft Band Data

If you've followed from any of my previous posts, you should know how to get yourselves connected with the Band and get sensor information in your app. Now I'll show you how to get it in a Background Task.

NOTE: If want to access the Heart Rate sensor of the Band, you'll need to get the user's consent before the background tasks is registered to the phone since this is a new requirement in the SDK. The best way to do this is when your first page loads up. Connect to the Microsoft Band using the following method:

  1. private static async Task CheckBandStatus()  
  2. {  
  3.     var bandInfo = (await BandClientManager.Instance.GetBandsAsync()).FirstOrDefault();  
  4.   
  5.     IBandClient bandClient = null;  
  6.   
  7.     bool isRunning = false;  
  8.   
  9.     if (bandInfo != null)  
  10.     {  
  11.         using (new DisposableAction(() => isRunning = true, () => isRunning = false))  
  12.         {  
  13.             try  
  14.             {  
  15.                 bandClient = await BandClientManager.Instance.ConnectAsync(bandInfo);  
  16.             }  
  17.             catch (Exception ex)  
  18.             {  
  19.                 // ToDo: Log error?  
  20.             }  
  21.   
  22.             if (bandClient != null)  
  23.             {  
  24.                 if (bandClient.SensorManager.HeartRate.GetCurrentUserConsent() != UserConsent.Granted)  
  25.                 {  
  26.                     await bandClient.SensorManager.HeartRate.RequestUserConsentAsync();  
  27.                 }  
  28.             }  
  29.         }  
  30.     }  
  31.   
  32.     if (bandClient != null)  
  33.     {  
  34.         bandClient.Dispose();  
  35.         bandClient = null;  
  36.     }  
  37. }  
If you've not implemented the DisposableAction class that I covered in a previous article, you can get a copy of it here to add to your solution: DisposableAction.cs. You'll be using it in the background task, so it's worth having.

The preceding code will bring a dialog up in your application that your user will need to accept. If they refuse to do so, you can keep this method calling the next time the user enters your application to remind them that they need to do so if they want to use the Band sensors to track information in your app.

Now let's get the Band data in your background class. We'll create a new asynchronous private method called GetBandData that will set up the Band connection and register to listen for events fired by the Band's sensors. I'm providing you with the setup code but if you'd like to understand what you're doing, please go back and read my previous posts.

  1. private async Task GetBandData()  
  2. {  
  3.     var bandInfo = (await BandClientManager.Instance.GetBandsAsync()).FirstOrDefault();  
  4.   
  5.     bool isRunning = false;  
  6.   
  7.     if (bandInfo != null)  
  8.     {  
  9.         using (new DisposableAction(() => isRunning = true, () => isRunning = false))  
  10.         {  
  11.             try  
  12.             {  
  13.                 this._bandClient = await BandClientManager.Instance.ConnectAsync(bandInfo);  
  14.             }  
  15.             catch (Exception)  
  16.             {  
  17.                 throw;  
  18.             }  
  19.   
  20.             if (this._bandClient != null)  
  21.             {  
  22.                 if (this._bandClient.SensorManager.HeartRate.GetCurrentUserConsent() != UserConsent.Granted)  
  23.                 {  
  24.                     // ToDo: Complete the deferral because we don't have consent to carry on  
  25.                     return;  
  26.                 }  
  27.   
  28.                 // Check the user is wearing the Band.  
  29.                 var bandContactState = await this._bandClient.SensorManager.Contact.GetCurrentStateAsync();  
  30.   
  31.                 if (bandContactState.State == BandContactState.NotWorn)  
  32.                 {  
  33.                     // ToDo: Complete the deferral because the user isn't wearing the band. No need to read sensors.  
  34.                     return;  
  35.                 }  
  36.   
  37.                 this._heartRateRead = false;  
  38.                 this._distanceRead = false;  
  39.                 this._skinTempRead = false;  
  40.                 this._bandClient.SensorManager.HeartRate.ReadingChanged += this.OnHeartRateChanged;  
  41.                 await this._bandClient.SensorManager.HeartRate.StartReadingsAsync();  
  42.   
  43.                 this._bandClient.SensorManager.Distance.ReadingChanged += this.OnDistanceChanged;  
  44.                 await this._bandClient.SensorManager.Distance.StartReadingsAsync();  
  45.   
  46.                 this._bandClient.SensorManager.SkinTemperature.ReadingChanged += this.OnSkinTemperatureChanged;  
  47.                 await this._bandClient.SensorManager.SkinTemperature.StartReadingsAsync();  
  48.             }  
  49.         }  
  50.     }  
  51.     else  
  52.     {  
  53.         // ToDo: Complete the deferral as we can't find the connected Band on the device.  
  54.     }  
  55. }  
As you can see in this method, we're making a connection to the Band client and keeping a reference to it so we can remember to dispose of it when we've done. If you let it dispose in this method, you'll lose the events that have been attached to the sensors and won't ever receive the readings.

We're creating 3 methods to attach to our sensors and these will look something as in the following:

  1. private void OnSkinTemperatureChanged(object sender, BandSensorReadingEventArgs<IBandSkinTemperatureReading> e)  
  2. {  
  3.     var skinTemperature = e.SensorReading.Temperature;  
  4.   
  5.     this._skinTempRead = true;  
  6.   
  7.     this._bandClient.SensorManager.SkinTemperature.StopReadingsAsync();  
  8.     this._bandClient.SensorManager.SkinTemperature.ReadingChanged -= this.OnSkinTemperatureChanged;  
  9.   
  10.     // Do something with the skin temperature?  
  11.   
  12.     this.CompleteReadings();  
  13. }  
  14.   
  15. private void OnDistanceChanged(object sender, BandSensorReadingEventArgs<IBandDistanceReading> e)  
  16. {  
  17.     var motionType = e.SensorReading.CurrentMotion;  
  18.     var pace = e.SensorReading.Pace;  
  19.     var speed = e.SensorReading.Speed;  
  20.   
  21.     this._distanceRead = true;  
  22.   
  23.     this._bandClient.SensorManager.Distance.StopReadingsAsync();  
  24.     this._bandClient.SensorManager.Distance.ReadingChanged -= this.OnDistanceChanged;  
  25.   
  26.     // Do something with the distance readings?  
  27.   
  28.     this.CompleteReadings();  
  29. }  
  30.   
  31. private void OnHeartRateChanged(object sender, BandSensorReadingEventArgs<IBandHeartRateReading> e)  
  32. {  
  33.     var healthRate = e.SensorReading.HeartRate;  
  34.   
  35.     this._heartRateRead = true;  
  36.   
  37.     this._bandClient.SensorManager.HeartRate.StopReadingsAsync();  
  38.     this._bandClient.SensorManager.HeartRate.ReadingChanged -= this.OnHeartRateChanged;  
  39.   
  40.     // Do something with the heart rate readings?  
  41.   
  42.     this.CompleteReadings();  
  43. }  
  44.   
  45. private async void CompleteReadings()  
  46. {  
  47.     if (this._heartRateRead && this._distanceRead && this._skinTempRead)  
  48.     {  
  49.         // Do something with the data we've received.  
  50.   
  51.         // ToDo: Complete the deferral as we are now done in the background task  
  52.     }  
  53. }  
We've now connected to the Microsoft Band, got the sensor data and have gotten to the end of our background task but the last thing we need to do is to disconnect from the Band if we're connected and completed the deferral. As you've probably noticed throughout the code snippets, I've purposely left areas that have notes to complete the deferral. Instead of all of these comments, we can create a method that does the disconnection and completion of the deferral. The reason we need to disconnect from the Band is that if we don't, the background task will throw an exception when it runs again.

Here's that method:

  1. private async void CompleteDeferral()  
  2. {  
  3.     if (this._bandClient != null)  
  4.     {  
  5.         this._bandClient.Dispose();  
  6.         this._bandClient = null;  
  7.     }  
  8.   
  9.     this._deferral.Complete();  
  10. }  
We've now come full circle and our background task is complete. The only thing left to do is now register it within the application to execute.

Registering the Microsoft Band background task

The first thing you'll want to do to get set up with the registration process is to reference your background project from your Windows Phone or Windows project.

Once you've done that, you'll need to make a change to your app's manifest file so that it supports the background task. Depending on how you're wanting to trigger this, you'll need to choose the correct trigger from the app manifest. In this tutorial, I'll show you a time based one that runs every 15 minutes.

This is how your app manifest should look:

Package.appxmanifest
                                                Figure:
Microsoft Band background task

Now, after your call in the first page of your app that asks for access to the Band's sensors, you'll want to register your background task and here is how you do that:
  1. private static async Task RegisterTimerTask()  
  2. {  
  3.     BackgroundAccessStatus backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync();  
  4.   
  5.     var builder = new BackgroundTaskBuilder { Name = TimerTaskId, TaskEntryPoint = typeof(BandUpdaterTask).FullName };  
  6.   
  7.     var trigger = new TimeTrigger(15, false);  
  8.   
  9.     builder.SetTrigger(trigger);  
  10.     builder.Register();  
  11. }  
This background task will register as a time-based trigger task that will run every 15 minutes.

You can now sit back and let your background task do all the work for your application!

If you have any questions, please feel free to leave them below and I will do my best to answer them.


Similar Articles