Windows Phone Mango–What’s New? (“Background Agents” – Part 5 of 8)

May 24, 2011

One of most requested and discussed features of Mango release is “multitasking”. In Mango the multitasking term has slightly different meaning than standard (PC) multitasking. Multitasking for Mango phones means ability to execute the code while application in not active and play audio started by the application in a background. This is achieved by Background Agents. In addition to them Mango also introduces APIs to download and upload files while application is in the background and add Reminders and Alarm to grab user attention.


This post will show how to use those features. During the post I’ll show how to build sample application which uses those features. The application’s UI is very simple:


image


Let’s start from background agents. The Background Agent are class libraries which “manifested” with application and capable of performing periodic tasks (or resource intensive task). To help starting with agents creation Visual Studio provides number of templates:


image


The Task Scheduler Agent is a “classical” background agent for running custom periodic task. Audio Streaming Agent enables background audio scenarios and Audio Streaming Agent enables creating the live audio streaming scenarios which requires custom MediaStreamSource implementation.


Note: The audio scenarios will not be covered in this post.


Added background scheduler agent project has only one class which derives from ScheduledTaskAgent class. By default it overrides two base member functions: OnInvoke and OnCancel.



  • OnInvoke called when phone invokes periodic task (or resource intensive task).
  • OnCancel invoked when agent request is getting canceled.

Background agent is a part of the application and as such it can access all resources available to the application. In this sample the background agent will update file in application’s IsolatedStorage with current DateTime timestamp. Let’s see the implementation details:

public class TaskScheduler : ScheduledTaskAgent
{
bool isCancelled;

protected override void OnInvoke(ScheduledTask task)
{
//TODO: Add code to perform your task in background
if (isCancelled)
{
NotifyComplete();
return;
}

using (IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication())
{
//Simulate the process running here..
byte[] data = System.Text.Encoding.UTF8.GetBytes(DateTime.Now.ToString());

using (IsolatedStorageFileStream file = iso.OpenFile(“data.dat”, System.IO.FileMode.OpenOrCreate))
{
file.Write(data, 0, data.Length);
file.Close();
}
NotifyComplete();
}
}

protected override void OnCancel()
{
base.OnCancel();

//TODO: This Task is cancelled, do necessary clean up
isCancelled = true;
}
}


The code is very simple. In order to make this class library as application’s background agent we need to add a reference to it from the main application. It will add a corresponding reference also in WMAppManifest.xml:

<Tasks>
<
DefaultTask Name=_defaultNavigationPage=MainPage.xaml/>
<
ExtendedTask Name=BackgroundTaskNavigationPage=MainPage.xaml>
<
BackgroundServiceAgent Specifier=ScheduledTaskAgentName=TheWorkerAgentSource=TheWorkerType=TheWorker.TaskScheduler
/>
</
ExtendedTask
>
</
Tasks>


From now on the class library is ready to serve as our application’s background agent. After deploying the application to he Windows Phone Emulator (or device) and navigating to Settings/Applications/background services you will find that our application has background service:


imageimage


and you can turn off background services to any of your applications.


Now let’s get back to the main app and wire the code for enabling/disabling running the background agent:

private void btnStartStopBgTask_Click(object sender, RoutedEventArgs e)
{
if (!isBackgroundTaskEnebaled)
{
PeriodicTask periodicTask = new PeriodicTask(“TheWorker”);
periodicTask.Description = “The worker task”;
periodicTask.ExpirationTime = DateTime.Now.AddDays(1);

ScheduledActionService.Add(periodicTask);
btnStartStopBgTask.Content = “Stop Background Task”;
isBackgroundTaskEnebaled = true;
}
else
{
ScheduledActionService.Remove(“TheWorker”);
btnStartStopBgTask.Content = “Start Background Task”;
isBackgroundTaskEnebaled = false;
}
}


This code snippet created a new PeriodicTask named “TheWorker” and scheduled it to run for 1 day. Removing the task is easy – all you need is just the name.


Note, that description is displayed at system background tasks page so give a meaningful names.


At any time you can query the task status by executing Find function:

ScheduledAction scheduledAction = ScheduledActionService.Find(“TheWorker”);
if (null != scheduledAction)
if (scheduledAction.IsEnabled)
{
//Task is running, do your logic…
}
else
{
//Task is not running, do your logic…
}

Next, let’s deal with reminders and alarms. Reminders are popups which be displayed above any active application (even when the phone screen is locked) much like reminder of upcoming meeting:


image


Let’s see how to add one:

private void btnAddReminder_Click(object sender, RoutedEventArgs e)
{
Reminder r = new Reminder(“important”);
r.Title = “Important!”;
r.Content = “Please get back to the application”;
r.BeginTime = DateTime.Now.AddSeconds(20);
r.NavigationUri = new Uri(“/MainPage.xaml?From=REMINDER”, UriKind.Relative);

ScheduledActionService.Add(r);
}


Clicking on reminder will navigate into the application and will use the provided URI (deep linking):


image


Note “REMINDED” added to the button caption when identified that application navigated from the reminder.


The Alarm is pretty similar to the Reminder; it will enable to use any application’s sound as alarm sound (or will use system alarm sound if not provided) but will not have an option to deep link into the application:

private void btnAddAlarm_Click(object sender, RoutedEventArgs e)
{
Alarm a = new Alarm(“theAlarm”);
a.RecurrenceType = RecurrenceInterval.Daily;
a.Content = “ALARM! Get back to the application”;
a.BeginTime = DateTime.Now.AddSeconds(10);
a.ExpirationTime = DateTime.Now.AddSeconds(20);
a.Sound = new Uri(“/Sounds/sound.wav”, UriKind.Relative);

ScheduledActionService.Add(a);
}


Receiving the alarm:


image


Last very exciting feature is a Background File Transfer. It enables to transfer files (both directions – upload and download) even when application is not active or tombstoned. Once application activated all the information from corresponding background transfers (events) will be delivered to the app. Let’s download big video file (~30Mb) using background transfer.

void StartDownload()
{
btr = new BackgroundTransferRequest(remoteVideoUri, localDownloadUri);
btr.TransferPreferences = TransferPreferences.AllowCellularAndBattery;
BackgroundTransferService.Add(btr);
btr.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>(btr_TransferProgressChanged);
btr.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(btr_TransferStatusChanged);
}


The event handlers allow to track the progress status. In our case TransfeProgressChanged event handler will add the progress percentage to the Background Download button:

void btr_TransferProgressChanged(object sender, BackgroundTransferEventArgs e)
{
double progress = e.Request.BytesReceived * 100 / e.Request.TotalBytesToReceive;
btnBackgroundDownload.Content = “Background Download (” + progress + “%)”;
}


and TransferStatusChanged event handler will deal with finished request removal and also will set the downloaded file as a source to MediaElement on the page:

void btr_TransferStatusChanged(object sender, BackgroundTransferEventArgs e)
{
if (btr.TransferStatus == TransferStatus.Completed)
{
btr.TransferProgressChanged -= btr_TransferProgressChanged;
btr.TransferStatusChanged -= btr_TransferStatusChanged;
BackgroundTransferService.Remove(btr);

Dispatcher.BeginInvoke(delegate
{
try
{
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
var file = isf.OpenFile(btr.DownloadLocation.ToString(),
FileMode.Open, FileAccess.Read);
mediaElement.SetSource(file);
}
}
catch (Exception ex)
{
MessageBox.Show(“Ooops, can’t load file. ” + Environment.NewLine + ex.Message);
}
});
}
}


Working sample:


image


First a few notes:



  • Big files will use WiFi by default to download , like marketplace applications does. Also in some cases big files will be downloaded only when device is connected to power source. In order to override this default behavior change the TransferPreferneces property of BackgroundTransferRequest instance.

    • btr.TransferPreferences = TransferPreferences.AllowCellularAndBattery;
       

  • When download finished it is up to the application to remove the unneeded request from the queue

    • var temp = BackgroundTransferService.Requests.FirstOrDefault();
      if (temp != null)
      BackgroundTransferService.Remove(temp);


  • The application limited to 5 requests in the BackgroundTransferService queue and need to manage their requests. If application adds more than 5 requests the BackgroundTransferService.Add() command will throw an exception.

See the video of working sample:






Background File Transfer, Alarms & Reminders working sample

 


The sample app  used for this post hosted here.


 


Stay tuned to the part 6 – “Fast Application Switch”.


Alex

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>