Quickstart: Sending an alarm in Windows 10

In Windows 10 UWP, alarms are simply Toast notifications with the "alarm" scenario. And to make an alarm appear at a specific time, you use a scheduled Toast notification.

Quick Summary

If you are already familiar with sending scheduled Toast notifications, you need to do two things, (1) use the "alarm" scenario on the Toast XML content, and (2) ensure you have at least one button on your Toast, as seen below. If you're not familiar with scheduled Toasts, please read this entire quickstart.

 
ToastContent toastContent = new ToastContent()
{
    Scenario = ToastScenario.Alarm,
    Visual = new ToastVisual() { ... },
    Actions = new ToastActionsCustom() { ... }
};
 


  
    ...
  

  
    ...
  

ToastAlarm

1. Install UWP Community Toolkit NuGet package

In order to create notifications via code, we strongly recommend using the UWP Community Toolkit Notifications library, which provides an object model for the notification XML content. You could manually construct the notification XML, but that is error-prone and messy. The Notifications library inside UWP Community Toolkit is built and maintained by the team that owns notifications at Microsoft.

Install Microsoft.Toolkit.Uwp.Notifications from NuGet (we're using version 1.0.0 in this documentation).

2. Add namespace declarations

Windows.UI.Notifications includes the Tile and Toast API's.

 
using Microsoft.Toolkit.Uwp.Notifications;
using Windows.UI.Notifications;

3. Construct the notification and specify scenario "alarm"

The Toast notification content includes text and images, and also buttons and inputs. Please see Quickstart: Sending a local toast notification and handling activations to see a full code snippet.

To make your Toast behave like an alarm (continuous looping audio, pops full screen on Mobile), set the Scenario to Alarm as seen below. And also ensure that you have at least one button on your Toast, or else it will not be displayed as an alarm.

 
ToastContent toastContent = new ToastContent()
{
    Scenario = ToastScenario.Alarm,
    Visual = new ToastVisual()
    {
        ... (omitted)
    },
    Actions = new ToastActionsCustom()
    {
        Inputs = { ... }
        Buttons =
        {
            ... (omitted)
        }
    }
};

ToastAlarm

4. Schedule the alarm to appear at a certain time

In order to make your Toast (alarm) appear at a specific time, you will need to use a scheduled Toast notification. This is essentially just a Toast notification with a delivery time.

You will construct a ScheduledToastNotification rather than a normal ToastNotification, and then you will call AddToSchedule rather than Show to schedule the notification for a future time.

 
DateTime alarmTime = DateTime.Now.AddMinutes(1);

// Only schedule notifications in the future
// Adding a scheduled notification with a time in the past
// will throw an exception.
if (alarmTime > DateTime.Now.AddSeconds(5))
{
    // Generate the toast content (from previous steps)
    ToastContent toastContent = GenerateToastContent();

    // Create the scheduled notification
    var scheduledNotif = new ScheduledToastNotification(
        toastContent.GetXml(), // Content of the toast
        alarmTime // Time we want the toast to appear at
        );

    // And add it to the schedule
    ToastNotificationManager.CreateToastNotifier().AddToSchedule(scheduledNotif);
}

Ensure your alarm will wake the phone from sleep

In order for your scheduled Toast to show exactly at the time you specified, you need to request access to background execution. Otherwise, while the phone is in sleep mode (screen off), your Toast may be delayed for an unknown amount of time (typically 30 seconds, sometimes longer), since the phone is conserving power.

Simply call RequestAccessAsync at some point in your app (like inside your App.xaml.cs). This only needs to be called once after your app is installed, but there is no harm in calling it multiple times.

 
await BackgroundExecutionManager.RequestAccessAsync();

Remove a scheduled alarm

If a user deletes or cancels their alarm, you will need to remove the ScheduledToastNotification that you scheduled.

Simply get a list of the currently scheduled Toast notifications from GetScheduledToastNotifications, find the notification that you want to remove, and call RemoveFromSchedule.

Note that if the alarm has already appeared, it will NOT appear in the scheduled notifications list. Instead, you can remove an alarm that has already appeared by using ToastNotificationManager.History.Remove, where you can remove a Toast by its Tag and/or Group.

 
var notifier = ToastNotificationManager.CreateToastNotifier();

// Get all scheduled notifications
var scheduled = notifier.GetScheduledToastNotifications();

// Find the one we want to remove
var toRemove = scheduled.FirstOrDefault(i => i.Id.Equals("userAlarm01"));

// And remove it
notifier.RemoveFromSchedule(toRemove);

Scheduling recurring alarms

The scheduled Toast API's do not have any recurrence options built in. That means you will have to use periodic background tasks to re-schedule your repeating alarms.

Here is a basic algorithm that you should use to continuously schedule your alarms.

  1. Schedule your alarms up to 5 days in advance
  2. Configure a TimeTrigger background task that runs every 24 hours
  3. Have that background task re-schedule the alarms up to 5 days in advance

The code snippet below registers a background task that runs every 24 hours, and when the task triggers, re-schedules all the alarms. See the full code sample on GitHub for more details.

Note that we are using the Single Process Model for background tasks, which is only supported in builds 14393 or newer.

 
private void RegisterPeriodicBackgroundTask()
{
    if (!BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals("DailyTask")))
    {
        var builder = new BackgroundTaskBuilder()
        {
            Name = "DailyTask"
        };

        builder.SetTrigger(new TimeTrigger(24 * 60, false)); // Every 24 hours

        builder.Register();

    }
}

protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
    var deferral = args.TaskInstance.GetDeferral();

    if (args.TaskInstance.Task.Name.Equals("DailyTask"))
    {
        // Re-schedule the notifications
        await DataModel.LoadAsync();
        DataModel.EnsureAllScheduled();
    }

    deferral.Complete();
}

Resources