Windows 8.1 Preview and ‘Alarm’/’Call’ Applications

First things first – although the Windows 8.1 RTM is available at the time of writing this post, I’m still working on the preview as I haven’t had a chance to catch breath and replace the OS.

Windows 8.1 came with a beautiful new application called “Alarms” which does exactly what you’d suspect based on the name and, to me, is interesting from a few points of view. The first is the user interface which provides a new control for setting times of alarms that I think is a really clever bit of UI;

image

I like that new “dial” control on the left hand edge of the screen a lot – it’s fantastic and fun to play with and it’s interesting to experiment using it with touch, mouse and keyboard as it’s pretty functional in all of those cases even though a first inspection might leave you thinking “hey, this is a touch only control, please go away with your keyboard and leave me alone” ; – )

If you want to get more detail about this UX then there was a video at BUILD which talked about it – I think it’s a great example of how a “simple” idea can be really well executed and how “simple” is rarely the same as “easy”;

There’s another interesting aspect of this application. If I set up an alarm such that it activates in, say, 1 minute’s time then when the alarm “fires” I get a toast notification;

image

but I can get a different toast notification out of this same alarms application that looks like this;

image

with the addition of the “snooze” and “dismiss” options but this only happens if I have gone into “PC Settings” and changed my one-and-only choice of alarm application to be this application as below;

image

This also drives a couple of other differences – namely;

  1. The audio accompanying the toast notification plays even if my system audio is muted.
  2. The alarm toast shows up even if my system is locked – i.e. on my lock screen.

I’m not sure how to get a screenshot of the lock-screen so I took a photo of it;

WP_20130926_001

and there it is.

There’s something else to say about this too – when I set up the alarm in the ‘Alarms’ app, I see some text;

image

So, clearly, what this means is that if the lid is closed on the laptop then I’m not going to get my alarm (I tested this – it was true Smile). But, does it mean that there’s a scenario for this app where I would get the alarm if the lid was closed on my machine? Yes, on systems that support it – like my ARM-based Surface RT device.

If I run the same application on my Surface RT device and I set the ‘Alarms’ app to be the alarm app on my lock-screen then I find that this little bit of warning text disappears and, sure enough, I can hit the power button on the device and I still get the alarm at the specified time as it wakes the device from whatever low-power sleep state it has put itself into.

Having used all this functionality I was then tempted to ask…

How Do They Do That?

Trying to be an Alarm App

The first thing that puzzled me was how do I make an “alarm” app? How do I tell the system that I want to do “alarm-type” functionality such that my application is available for selection from the “PC Settings” screen as in;

 

image

I ran up Visual Studio 2013 and made a new project and ran it to install it and, naturally, it didn’t show up as an option in that drop-down that lets me choose alarm aps. Clearly, there must be some meta-data that I need to add to my application in order to say “I am an alarm app”.

It took me a while to find that metadata in Visual Studio 2013 Preview – I’m not sure if there’s a missing piece of UI or something but I couldn’t find any setting that said “this app is a lock-screen-alarm-app”. In the end, I did what anyone would do and downloaded the alarm sample from the Windows SDK for 8.1 and I poked around in the package manifest file until I spotted this little XML fragment;

image

and so I added one of those to the manifest of my own application although I initially didn’t specify that I was doing audio/timer background tasks as well like this sample does. That almost got me into that selection dialog for the lock screen but the system (as always) was smarter than me and said “no”;

image

and so clearly I need to do a little bit more than just having this “extension” – it seems reasonable to also say that my app can be put on the lock-screen and to do that it’ll need a badge logo so I filled those in;

image

But the build system caught me out again in that it expects an app that’s going onto the lock-screen to be able to do something useful on the lock-screen and, realistically, it’d need some kind of background task to be able to be useful. So…I get asked to sort that out;

image

and so I go and add into the manifest the idea that I might be doing background tasks although I can see a situation where an alarm app might not actually need background tasks and I’m not planning to implement one here but I add the metadata at least;

image

and then I build, deploy this app and it shows up as an option for the lock-screen;

image

so I seem to have at least got started. What about knowing whether my app is the lock-screen app or not and, more than this, how does my app know whether it is able to wake the device or not?

Checking Alarm App Status

This one turns out to be a fairly simple API call. I can add a button to my blank UI and stick some code behind it;

    async void Button_Click(object sender, RoutedEventArgs e)
    {
      var status = AlarmApplicationManager.GetAccessStatus();
      bool ask = false;

      switch (status)
      {
        case AlarmAccessStatus.AllowedWithWakeupCapability:
          // The full monty - excellent.
          break;
        case AlarmAccessStatus.AllowedWithoutWakeupCapability:
          // The semi monty - maybe display some UI to tell the user their alarm won't ring
          // if the device is not on.
          break;
        case AlarmAccessStatus.Denied:
          // No monty. Not much we can do there as the user has already said "nope".
          break;
        case AlarmAccessStatus.Unspecified:
          // Null monty. We could ask?
          ask = true;
          break;
        default:
          break;
      }
      if (ask)
      {
        status = await AlarmApplicationManager.RequestAccessAsync();
      }
    }

the switch statement is only really there to illustrate the options in the enumeration but you get the idea. Once my app knows that it is the lock-screen-alarm-app it can then try and raise a notification. On first run my app displays;

image

to see if it can convince the user to change their alarm app to be my alarm app – if the user clicks “No” here then subsequent requests to RequestAccessAsync() will return Denied.

Raising a Notification

Whether my app is the lock-screen-alarm-app or not, I can still raise notifications to the user – it’s just a question of whether those notifications would;

  1. Wake the device if it was off.
  2. Show up if the device was locked.
  3. Sound if the sound was muted.

But, regardless, if I want to raise a toast notification I need to say that I’m going to be doing that in my manifest;

image

and then I need to drop into the mechanics of sending a toast notification at some point in the future. I added another button to my UI and raised a toast notification in 10 seconds time;

      // To make toast, first we need bread.
      XmlDocument xmlContent = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01);

      // Now need something to put on the bread.
      var textElement = xmlContent.SelectSingleNode("//text");
      textElement.InnerText = "This is my toast content";

      // Now need a notifier.
      ToastNotifier notifier = ToastNotificationManager.CreateToastNotifier();

      // Now need a toast.
      ScheduledToastNotification toast = new ScheduledToastNotification(
        xmlContent,
        DateTimeOffset.Now.AddSeconds(10),  // delivery time
        TimeSpan.FromSeconds(60),           // snooze interval
        2);                                 // max number of snoozes

      // Ask for the toast.
      notifier.AddToSchedule(toast);

Now, this is kind of nice and it definitely displays the toast and even on the lock screen but if my system audio is muted I don’t hear anything and nor does it have those nice dismiss/snooze buttons on it. There’s additional schema needed for that as described on MSDN and I don’t think that schema was present for Windows 8.0. Trying to add an “alarm” command into that XML;

      // To make toast, first we need bread.
      XmlDocument xmlContent = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01);

      // Now need something to put on the bread.
      var textElement = xmlContent.SelectSingleNode("//text");
      textElement.InnerText = "This is my toast content";

      var commandsElement = xmlContent.CreateElement("commands");
      commandsElement.SetAttribute("scenario", "alarm");

      var snoozeElement = xmlContent.CreateElement("command");
      snoozeElement.SetAttribute("id", "snooze");
      var dismissElement = xmlContent.CreateElement("command");
      dismissElement.SetAttribute("id", "dismiss");

      commandsElement.AppendChild(snoozeElement);
      commandsElement.AppendChild(dismissElement);

      xmlContent.DocumentElement.AppendChild(commandsElement);

      // Now need a notifier.
      ToastNotifier notifier = ToastNotificationManager.CreateToastNotifier();

      // Now need a toast.
      ScheduledToastNotification toast = new ScheduledToastNotification(
        xmlContent,
        DateTimeOffset.Now.AddSeconds(10),  // delivery time
        TimeSpan.FromSeconds(60),           // snooze interval
        2);                                 // max number of snoozes      

      // Ask for the toast.
      notifier.AddToSchedule(toast);

Still no audio though in the case where my system audio is muted. I added a little bit of extra code in after line 18 to choose a specific audio sound;

      var audioElement = xmlContent.CreateElement("audio");
      audioElement.SetAttribute("src", "ms-winsoundevent:Notification.Looping.Alarm3");
      audioElement.SetAttribute("loop", "true");
      xmlContent.DocumentElement.AppendChild(audioElement);

and that seemed to do the trick but only once I told the toast that it was a toast with a long duration;

  xmlContent.DocumentElement.SetAttribute("duration", "long");

and that seemed to give me a toast with dismiss/snooze that appeared on the lock-screen and that played audio even over a muted system audio.

What I’m not 100% clear on is whether there is any way for the app’s code to handle the dismiss/snooze scenarios or whether they are just automatically handled by the system – snooze seems to work that way and, of course, dismiss just does what it says it does so there might not really be any need for additional custom processing around those commands. There is another command though…

The Mysterious Call Command

Alongside that “scenario=’alarm’” option, the docs mention another scenario – incomingCall with additional commands for video/voice/decline.

I’m not sure whether there’s an app installed on the system (Skype/Lync etc) that is yet upgraded to support this functionality but there’s another sample over in the SDK that mocks it up.

This one had me puzzled because I could see how an alarm toast on the lock-screen could work when the options are “Snooze/Dismiss”.

But how would a toast on the lock-screen that was trying to signal an incoming call work when the options are “Decline/Voice/Video”? You really need to be able to switch to the app in order to have a video conversation but the app is stuck behind the lock-screen so how does that work?

It works because the app runs “under” the lock-screen. This was news to me Smile

Here’s how the sample looks. I’m sitting on my lock screen;

image

and then the toast notification arrives and I can decline or choose voice/video if either or both of those are offered. I choose voice;

image

and the app is running despite the fact that the machine is still locked and the UI gives me an option to unlock the machine if I want to or to end the call;

image

Pretty interesting. Now…for a call like this to actually come in to a machine with the screen locked I think you’d have to be running some kind of background task with a trigger that could be activated with the screen locked – examples would be;

  1. Control Channel Trigger
  2. Push Notification Trigger

but I suspect that the former is most likely – this is a trigger that fires when data arrives down an open socket. The flow goes something like this;

  1. User executes some action which allows the app to execute code. This might be running the app interactively. It might be that they log into the system and app is on their lock-screen and has a background task that runs code when they log in. One way or another, the app gets to run code.
  2. The app code opens up a socket to a backend service like an IM service or a call service or similar.
  3. The app hands that open socket to the system with a ControlChannelTrigger.
  4. The app code stops running because the background task ends or the interactive app is suspended or similar.
  5. The system watches the socket and when data arrives down it (incoming call) it executes whatever background task the app has associated with the ControlChannelTrigger.
  6. The background task notifies the user that there is an incoming call via one of these new incomingCall notifications which can work even if the machine is locked or asleep (in some cases).
  7. The user accepts the call and takes the call possibly on the lock-screen.

To get my sample code to act correctly for the “incomingCall” scenario, the first thing that it seems I’ve got to do is change my metadata in my package manifest. I modified my Extensions section;

image

and that seems to give me the option of sending a toast containing the “incomingCall” scenario which I can build up from code again and send;

      // To make toast, first we need bread.
      XmlDocument xmlContent = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01);

      xmlContent.DocumentElement.SetAttribute("duration", "long");

      // Now need something to put on the bread.
      var textElement = xmlContent.SelectSingleNode("//text");
      textElement.InnerText = "This is my toast content";

      var commandsElement = xmlContent.CreateElement("commands");
      commandsElement.SetAttribute("scenario", "incomingCall");

      var declineElement = xmlContent.CreateElement("command");
      declineElement.SetAttribute("id", "decline");
      var videoElement = xmlContent.CreateElement("command");
      videoElement.SetAttribute("id", "video");
      videoElement.SetAttribute("arguments", "video arguments");
      var voiceElement = xmlContent.CreateElement("command");
      voiceElement.SetAttribute("id", "voice");
      voiceElement.SetAttribute("arguments", "voice arguments");

      commandsElement.AppendChild(declineElement);
      commandsElement.AppendChild(videoElement);
      commandsElement.AppendChild(voiceElement);

      xmlContent.DocumentElement.AppendChild(commandsElement);

      var audioElement = xmlContent.CreateElement("audio");
      audioElement.SetAttribute("src", "ms-winsoundevent:Notification.Looping.Call");
      audioElement.SetAttribute("loop", "true");
      xmlContent.DocumentElement.AppendChild(audioElement);

      // Now need a notifier.
      ToastNotifier notifier = ToastNotificationManager.CreateToastNotifier();

      // Now need a toast.
      ScheduledToastNotification toast = new ScheduledToastNotification(
        xmlContent,
        DateTimeOffset.Now.AddSeconds(10));

      // Ask for the toast.
      notifier.AddToSchedule(toast);

and that seems to work fine in the sense that the toast message pops up and that’s also true on the lock-screen (as long as the app is set up as a lock-screen app – it no longer needs to be the alarm app, just a lock-screen app).

It’s possibly a little “odd” to use a scheduled toast notification here because you’d imagine an incoming call would need an immediate toast notification – I’m using scheduled here because it gives me time to lock the machine and test it out.

The only question that left for me was how tapping on the video/voice buttons is handled by the app.

What I picked up from the SDK sample is that the app gets activated when I tap on the video/voice buttons and not, as you might expect, when I tap on the decline button.

The activation carries the event args that were specified in the toast message – here that is in Visual Studio’s debugger;

image

It’s clear then how a piece of state can be passed from the commands present in the toast message payload through to the app as it is activated in response to the user’s selection of a video/voice option. I’m not 100% sure that I have it quite in my mind how this would work in an incoming call scenario for VOIP but maybe it’s something like;

  1. User 1 logs into machine. Background task runs and opens up some socket to a VOIP cloud server.
  2. System monitors socket on the apps’ behalf.
  3. User 1 locks machine, kicks back, drinks tea.
  4. User 2 logs into machine. Runs up VOIP client. Calls User 1.
  5. User 2’s app sends “call user 1” message to some VOIP cloud server.
  6. VOIP cloud server finds User 1’s socket and sends data down it to say “incoming call from User 2”.
  7. Background task runs on User 1’s machine, picks up the socket data, perhaps persists some details of the incoming call and fires up “incomingCall” toast message.
  8. User 1 gets toast message on lock screen, clicks on “voice” or “video” option.
  9. User 1 runs app on lock screen. App picks up details of how to connect the call that were persisted by the background task in step 6 above.
  10. Call happens.
  11. Life is good.

That’s my best guess but I’ll see if I can update this post if I figure it out more definitively – there used to be a whitepaper on VOIP apps for Windows 8.0 so I’ll see if I can find an updated version for Windows 8.1 and will add a link to that here if I do. In the meantime, if you know better and want to correct those steps – feel free to post modifications below!