Chapter 8. Tile and toast notifications

The Start screen is the users’ personal dashboard, containing information they care about. It consists of tiles, all nicely ordered with animating content. One glance shows you new email, the latest price of your favorite stocks, when and what your next appointment is, the latest weather information for locations you care about, and so on.

For developers, these tiles provide tremendous advantages compared to other platforms. Showing useful information in a tile compels the user to open your app more often. And the more time spent in your app, the better it is for you as an app developer if your app offers in-app advertising or in-app purchases. In addition to updating tile content, your app can place a badge over a tile drawing the user’s attention to important information such as new emails or missed calls. The Start screen is designed to show information the user cares about. So users control whether your app’s tile can reside on their Start screen, the size of the tile, and whether your app can update the tile’s contents. Your app cannot control these things. In addition to containing tiles and badges, your app can also pop up toast notifications that inform the user of time-critical information, such as an incoming call or meeting reminders. Again, the user is in control and can silence toast notifications produced by your app.

In Chapter 3 you saw that the system gives CPU time only to Windows Store apps in the foreground. So you might wonder how an app can update its tile’s contents or pop up a toast notification when the app is in the background or not running at all. Tiles, badges, and toast notifications are updated using four techniques, summarized in Table 8-1. All of these techniques are explained in this chapter.

Table 8-1. Four techniques to update tiles, badges, and toast notifications.

Update technique

Applies to

Description and examples

Foreground

Tile

Badge

Toast

App’s code updates the notification while the app is running in the foreground.

Examples: Music app shows the current song; Game app shows the high score; Clear the badge when the app activates to reset an “unseen” notification (described later).

Scheduled

Tile

Toast

App’s code schedules the notification update for a future time.

Examples: Calendar reminders, countdowns to something

Periodic

Tile

Badge

App’s code instructs Windows to periodically poll an HTTP(S) server. This is great for distributing the same content to a wide audience. You specify the URI, start time, and frequency of recurrence (such as a ½ hour, 1 hour, 6 hours, 12 hours, or 24 hours).

Examples: Weather update, “daily deals” site

Push (WNS)

Tile

Badge

Toast

App’s companion server pushes the notification to Windows on demand. This is great for personalized data, real-time data, or both.

Examples: Breaking news, sports updates, social updates, incoming messages

Tiles and badges

Your app can use its tile for a variety of purposes. Of course, users can always tap or click a tile to launch an app. If the app is in the suspended state when the user taps its tile, the system brings the app back to the foreground, thereby using the tile as a mechanism to switch tasks. Users select one or more tiles by right-clicking and pressing the spacebar, or with a tap and hold gesture. The Start screen’s app bar offers options to control the selected tiles. Specifically, the user can unpin an app’s tile from the Start screen, uninstall the app, change the tile’s size, and disable tile updates by tapping Turn Live Tile Off. (See Figure 8-1.)

App bar on the Start screen for a selected tile.

Figure 8-1. App bar on the Start screen for a selected tile.

A user can remove personal information from all tiles (for example, when giving a presentation) via Settings pane > Tiles > Clear. Also, users can rearrange their tiles, group their tiles, and assign names to groups. In addition, users can zoom out to see more tiles using semantic zoom.[63] Desktop apps can also have tiles; however, the tiles are always square and their content cannot be updated. In addition, Internet Explorer can pin a website to the Start screen; this tile can update its contents periodically. For more information, see http://www.buildmypinnedsite.com/.

The Start screen supports four tile sizes (as shown in Figure 8-2). An app must provide static logos (images) for tile sizes that Windows requires and can optionally provide logos for tile sizes the app wishes to support. An app must also provide a logo used for the app’s branding. The app must provide some additional logos if it supports certain background tasks that allow the app to be placed on the user’s lock screen. (See Chapter 9 for more information.) Table 8-2 lists the logos related to Start screen tiles, branding, and the lock screen.

The Start screen showing four small tiles (top left), one medium tile (with “Mail” as the branding name and “1” as the badge), one wide tile (bottom left, with a branding logo), and one large tile (with “Weather” as the branding name).

Figure 8-2. The Start screen showing four small tiles (top left), one medium tile (with “Mail” as the branding name and “1” as the badge), one wide tile (bottom left, with a branding logo), and one large tile (with “Weather” as the branding name).

Table 8-2. App logos.

End-user term

Developer term

Manifest file name

Mandatory

Where shown

Small

Square 70×70

Square70×70Logo.png

Start screen. This tile is always static; you cannot dynamically change its contents.

Medium

Square 150×150

Logo.png

Start screen

Wide

Wide 310×150

WideLogo.png

Start screen

Large

Square 310×310

Square310×310Logo.png

Start screen

(N/A)

Square 30×30

SmallLogo.png

Bottom/left portion of the tile, bottom/right portion of the toast, Start screen semantic zoom, App list, Search/Share panes, Open With dialog box

(N/A)

Badge 24×24

BadgeLogo.png

For some background tasks

Lock screen. The “badge logo” identifies the app on the user’s lock screen. It is the app’s badge. This logo is not related to the badge placed on a tile.

In Microsoft Visual Studio, you specify settings for your app’s tile using the Visual Assets tab of the manifest designer as shown in Figure 8-3. The tile background color shows through the logo’s transparent pixels. The file names you specify in the manifest are for your app’s static tiles. These are the tiles the user sees unless your app executes some code that updates the tiles’ contents or unless you set a URI template via the manifest’s Tile Update settings. (See the Updating a tile periodically section for more information.)

Tile settings in the manifest.

Figure 8-3. Tile settings in the manifest.

To accommodate users with screens of varying dots-per-inch (DPI), you should provide four DPI scalings for each tile logo: 80%, 100%, 140%, and 180%. So, when creating your app’s medium logo, you should create four files: Logo.scale-80.png, Logo.scale-100.png, Logo.scale-140.png, and Logo.scale-180.png. For more information, see the Accessing read-only package files section in Chapter 5.

Updating a tile when your app is in the foreground

Your app describes its tile’s content to Windows declaratively. That is, your app creates an XML document describing the desired contents of the tile and then your app passes this XML document to Windows. Windows predefines several XML tile templates; each offers a different way to lay out text and images on the tile.[64] Windows then parses the document, builds the tile’s image, and displays that image on the user’s Start screen. So, in your code, you first start by creating an XML document that matches one of the predefined templates. The XML schema for tiles is documented at http://msdn.microsoft.com/en-us/library/windows/apps/br212859.aspx. The catalog of tile templates, along with examples of what each template produces, is documented at http://msdn.microsoft.com/en-us/library/windows/apps/hh761491.aspx.

Let’s look at some code that updates your app’s tile. Here we’ll update a square 150-pixel by 150-pixel tile. You start by creating an XML document matching one of the predefined templates. To simplify this, WinRT provides an API that returns a predefined template. Here is an example of how to get an empty, predefined XML template:

XmlDocument tileXml =
   TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150Text01);

Once you have this template, you modify the tile’s text by retrieving the text element from the XmlDocument and appending a text node to it:

tileXml.GetElementsByTagName("text")[0].AppendChild(tileXml.CreateTextNode("New text"));

The XML document now looks like this:

<tile>
   <visual version="2">
      <binding template="TileSquare150x150Text01" fallback="TileSquareText01">
         <text id="1">New text</text>
         <text id="2"></text>
         <text id="3"></text>
         <text id="4"></text>
      </binding>
   </visual>
</tile>

Now you create a TileNotification object, passing it the XmlDocument. A TileNotification object offers some additional properties to help manage the lifetime of the tile notification; these will be described later. Then, to update your app’s tile, you use the TileUpdateManager to create a TileUpdater object and then use this object to update your tile:

TileNotification tileNotification = new TileNotification(tileXml);
TileUpdater updater = TileUpdateManager.CreateTileUpdaterForApplication();
updater.Update(tileNotification);

If your app supports multiple tile sizes, you must prepare an XML template for each size, package all the templates together into a single XML document, create one TileNotification object from the XML document, and then update the tile. Remember, the user can change a tile’s size whenever he wants. This is why you must include XML templates for all tile sizes; the system remembers the last TileNotification object you sent to it and will update the tile’s content automatically if the user later changes its size.

This code demonstrates how to create an XML template for a square 150-by-150 tile and another XML template for a wide 310-by-150 tile, merge them together, and update the tile’s content:

// Create square 150x150 tile template
XmlDocument tileXml =
   TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150Text01);
tileXml.GetElementsByTagName("text")[0].AppendChild(tileXml.CreateTextNode("New text"));
// Create wide 310x150 tile template
XmlDocument wide310x150Xml =
   TileUpdateManager.GetTemplateContent(TileTemplateType.TileWide310x150ImageAndText01);
wide310x150Xml.GetElementsByTagName("text")[0]
   .AppendChild(wide310x150Xml.CreateTextNode("New text"));
wide310x150Xml.GetElementsByTagName("image")[0].Attributes.GetNamedItem("src")
   .NodeValue = "ms-appx:///Assets/snowday.jpg";
// Merge the two tile templates into a single XML document:
IXmlNode node =
   tileXml.ImportNode(wide310x150Xml.GetElementsByTagName("binding").Item(0), true);
tileXml.GetElementsByTagName("visual").Item(0).AppendChild(node);

The resulting XML document looks like this:

<tile>
   <visual version="2">
      <binding template="TileSquare150x150Text01" fallback="TileSquareText01">
         <text id="1">New text</text>
         <text id="2"></text>
         <text id="3"></text>
         <text id="4"></text>
      </binding>
      <binding template="TileWide310x150ImageAndText01" fallback="TileWideImageAndText01">
         <image id="1" src="ms-appx:///Assets/snowday.jpg"/>
         <text id="1">New text</text>
      </binding>
   </visual>
</tile>

Note how we set the image on the wide tile. When setting an image element’s src attribute, the URL can start with any of the values from Table 8-3.

Table 8-3. URL prefixes for tile images.

URL prefix

Description

Notes

ms-appx:///

Use this to refer to an image file shipped in your app’s package.

The three slashes after the colon are required. See Chapter 5 for more details.

ms-appdata:///local/

Use this to refer to an image file existing in your app’s local storage folder. Note you cannot refer to images under your app’s temporary or roaming folders.

http://

or

https://

Use this to refer to an image that should be downloaded from a web server.

The system can automatically concatenate a query string to the URL indicating the required image scale (80, 100, 140, 180), contrast, and language based on the user’s current environment.

Important

The system supports JPEG, PNG, and GIF image formats only. In addition, images must not exceed 200 KB, and neither the height nor the width can be more than 1024 pixels. If your image violates any of these rules, the system discards your XML and does not update your app’s tile. This can be quite frustrating, because the APIs do not provide you any indication of failure. However, the system will write an error entry to this event log at Applications And Services Logs > Microsoft > Windows > Apps > Microsoft-Windows-TWinUI-Operational.

Placing a badge on a tile

Placing a badge on a tile is similar to how you update a tile’s contents. Instead of using TileUpdateManager, you use BadgeUpdateManager to retrieve one of the two BadgeTemplateTypes: BadgeNumber or BadgeGlyph. Then you modify the XmlDocument, use the document to create a BadgeNotification, and hand the notification to the badge updater:

XmlDocument xmlBadge = BadgeUpdateManager.GetTemplateContent(BadgeTemplateType.BadgeNumber);
// Passing BadgeTemplateType.BadgeGlpyh to GetTemplateContent returns identical XML as above
XmlNodeList badgeAttributes = xmlBadge.GetElementsByTagName("badge");
badgeAttributes[0].Attributes.GetNamedItem("value").NodeValue = "7";  // Set value to a number
BadgeNotification badgeNotification = new BadgeNotification(xmlBadge);
BadgeUpdater bu = BadgeUpdateManager.CreateBadgeUpdaterForApplication();
bu.Update(new BadgeNotification(xmlBadge));

To see the XML schema for badges, go to http://msdn.microsoft.com/en-us/library/windows/apps/br212851.aspx. To see the catalog of badge templates, visit http://msdn.microsoft.com/en-us/library/windows/apps/hh779719.aspx. This catalog is also shown in Figure 8-4. You use the status string in the first column to have the badge show a glyph. To have the previous code show a glyph instead of a number, change the fourth line of code to this:

badgeAttributes[0].Attributes.GetNamedItem("value").NodeValue = "attention";
The badge glyphs you can put on a tile.

Figure 8-4. The badge glyphs you can put on a tile.

To reset a tile back to its static logo or remove a badge from a tile, just call TileUpdateManager’s or BadgeUpdateManager’s Clear method:

// Reset the tile back to its static logo & remove its badge:
TileUpdateManager.CreateTileUpdaterForApplication().Clear();
BadgeUpdateManager.CreateBadgeUpdaterForApplication().Clear();

Live tiles typically show content that is fresh, and there are occasions when it is better to show nothing at all instead of showing old content. For example, you should not show weather temperatures or stock prices that are seven days old or older. To enable you to automatically remove old content, TileNotification objects offer an ExpirationTime property. The system automatically deletes a tile notification when its time expires and reverts the tile back to its static logo:

TileNotification tileNotification = new TileNotification(tileXml) {
   ExpirationTime = DateTimeOffset.Now.AddDays(7)
};
updater.Update(tileNotification);

Animating a tile’s contents

There is a quick and easy way to animate a tile using predefined peek templates. Each peek template describes two views of a tile, and the Start screen automatically cycles from one view to the other every few seconds. The following XML template is the TileSquarePeekImageAndText01 template:

<tile>
  <visual version="2">
    <binding template="TileSquare150x150PeekImageAndText01"
             fallback="TileSquarePeekImageAndText01">
      <image id="1" src=""/>
      <text id="1"></text>
      <text id="2"></text>
      <text id="3"></text>
      <text id="4"></text>
    </binding>
  </visual>
</tile>

As documented, when the system receives XML containing this template, it shows one square image without text on the top, one header string in larger text on the first line, and three strings of regular text on each of the next three lines on the bottom. Figure 8-5 shows an example of this tile’s appearance.

The contents of a peek square tile (for which the system cycles between the top and bottom automatically).

Figure 8-5. The contents of a peek square tile (for which the system cycles between the top and bottom automatically).

The system shows the top half of the contents in the tile, waits a few seconds, shows the bottom half, waits a few seconds, and shows the top half again. This cycling happens continuously and automatically while the user is looking the Start screen.

In addition to using peek templates, your app can queue up to five tile notifications to a single tile and the Start screen will automatically cycle through them. You enable queuing by calling TileUpdateManager’s EnableNotificationQueue method and passing in true. The following code creates five tile notifications and queues them to the app’s tile:

TileUpdater tu = TileUpdateManager.CreateTileUpdaterForApplication();
tu.EnableNotificationQueue(true);  // Enable queuing up to 5 notifications
// Queue 5 tile notifications to our app's tile:
for (Int32 tileNum = 0; tileNum < 5; tileNum++) {
   XmlDocument tileXml =
      TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150Text01);
   tileXml.GetElementsByTagName("text")[0].AppendChild(tileXml.CreateTextNode("#" + tileNum));
   tu.Update(new TileNotification(tileXml));
}

Offering multiple tile notifications allows apps to cycle through multiple news feeds, email messages, stock prices, or weather temperatures, giving the user a lot of information at a glance. For developers, it becomes a challenge not to provide too much information.

Once you associate a set of tile notifications with a tile, your app can be suspended or terminated; the Start screen will still cycle through the notifications, giving the user the illusion that your app is still running. Consider how power and CPU efficient it is to have only the Start screen do this work for all apps instead of having every app update its own tile by executing code in the background.

If you add more than five tiles to the queue, the system replaces the oldest using a first-in, first-out (FIFO) algorithm. However, your app can replace a specific tile notification by specifying a tag string:

TileNotification tileNotification = new TileNotification(tileXml) { Tag = "MSFT" };

Now when we want to replace this tile notification, we just specify the same tag string:

TileNotification tileNotification1 = new TileNotification(tileXml) { Tag = "MSFT" };
tu.Update(tileNotification1);

Tag strings have a 16-character limit, and your app can use tags only to replace or remove tile notifications. Unfortunately, if the user launches your app via its tile, your app will not receive the tag of the currently visible tile notification. So your app can’t display different content based on a specific tile notification. If you want your app to navigate to different content, your app can use secondary tiles (discussed in the Secondary tiles section).

So far, the methods shown require your app to be running in the foreground to update its tile’s content. In addition, your app can implement a background task. (See Chapter 9.) Background tasks can run periodically or when a trigger (for example, a user logon) occurs. Although the system does not allow background tasks to manipulate an app’s user interface in any way, a background task’s code can update the app’s tile or badge, or show a toast notification.

In addition, there are several techniques allowing your app to update its tile’s content while no code is running. The next section, Updating a tile at a scheduled time shows how to schedule a tile notification to activate itself in the future. The Updating a tile periodically section shows how to have the system periodically poll a web server for a new XML template. And, much later in this chapter, the Windows Push Notification Service (WNS) section shows how you can manage your own web server in the cloud that can push XML templates down to your app’s tile for a particular user on a particular machine.

Updating a tile at a scheduled time

In your app, you can use ScheduledTileNotification to have the system update your app’s tile sometime in the future:

XmlDocument tileXml =
   TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150Text01);
tileXml.GetElementsByTagName("text")[0].AppendChild(tileXml.CreateTextNode("Eat lunch"));
ScheduledTileNotification stn =
   new ScheduledTileNotification(tileXml, DateTimeOffset.Now.AddHours(2)) {
      ExpirationTime = DateTimeOffset.Now.AddMinutes(30)
   };
TileUpdateManager.CreateTileUpdaterForApplication().AddToSchedule(stn);

Here we schedule a tile notification that activates itself in two hours. Additionally, the tile notification expires 30 minutes from the time it is scheduled. You can schedule up to 4,096 tiles in advance. This is useful if you want to implement a countdown timer.

Updating a tile periodically

Your app can tell the system to get tile notifications from a web server periodically. Here is an example that has the Start screen poll a web server of your app’s choosing every 30 minutes for a new tile template:

TileUpdater tu = TileUpdateManager.CreateTileUpdaterForApplication();
tu.StartPeriodicUpdate(
   new Uri("http://WintellectNOW.blob.core.windows.net/public/TileTemplates.xml"),
   DateTimeOffset.UtcNow.AddSeconds(10), PeriodicUpdateRecurrence.HalfHour);

Your app can, of course, use the URL to pass additional information to the web server in a query string. For example, your app can send a ZIP code to indicate location information that the web server can use to return an XML template targeted for your app’s specific needs (“http://SomeWeatherService.com?Zip=98033”).

Call TileUpdateManager’s StopPeriodicUpdate method to have the Start screen stop polling your web server.

In your app’s package manifest, you can enable periodic updates for your app’s tile. This allows your app’s tile to start showing useful information right after the user installs your app. See the Tile Update section on the Application tab in Visual Studio’s package manifest designer.

Secondary tiles

In addition to an app’s main tile, an app can have one or more secondary tiles on the Start screen. Secondary tiles have the same capabilities as the app’s main tile, including badges, peek templates, queuing up to five tile notifications, scheduled updates, periodic updates, and also Windows Push Notifications. When a user launches your app from a secondary tile, the system passes in a launch parameter to your app so that your app can display different content depending on which tile the user tapped. Examples of secondary tiles are stock-ticker apps with several tiles for different stocks or a weather app with a tile for each geographic location. Having a secondary tile launch your app to a specific stock or location within your app is sometimes referred to as deep linking.

Because users are always in control of their Start screen, your app can’t just add a secondary tile to it. Instead, your app calls a WinRT API that prompts the user to pin a secondary tile to the Start screen. The user can approve or deny this operation. Most apps expose functionality to add secondary tiles through a Pin To Start button in the app bar, but this is not a requirement. Here is an example of how you create a secondary tile for your app:

String baseUri = "ms-appx:///Assets/";
String tileId = "SecondaryTile";
SecondaryTile tile = new SecondaryTile(tileId) {    // ID passed to OnLaunched
   Arguments = "Some argument",                     // Args passed to OnLaunched (can't be "")
   DisplayName = "2nd tile-Display Name",
   RoamingEnabled = true                            // Default is true
};
// Properties common to all tile sizes:
tile.VisualElements.BackgroundColor = Colors.Green;
tile.VisualElements.ForegroundText = ForegroundText.Light;  // Dark=#2A2A2A, Light=#FFFFFF
tile.VisualElements.Square30x30Logo = new Uri(c_baseUri + "SmallLogo.png"); // Optional
// Select tile sizes to offer the user:
tile.VisualElements.Square150x150Logo = new Uri(c_baseUri + "Logo.png"); // Mandatory
tile.VisualElements.ShowNameOnSquare150x150Logo = false;
// The following logos are optional:
tile.VisualElements.Square70x70Logo = new Uri(c_baseUri + "Square70x70Logo.png");
tile.VisualElements.Wide310x150Logo = new Uri(c_baseUri + "WideLogo.png");
tile.VisualElements.ShowNameOnWide310x150Logo = true;
tile.VisualElements.Square310x310Logo = new Uri(c_baseUri + "Square310x310Logo.png");
tile.VisualElements.ShowNameOnSquare310x310Logo = true;
// Ask user to create the secondary tile:
Boolean userCreated = await tile.RequestCreateAsync();

Because you can’t define any settings for secondary tiles in the manifest, you have to specify all the properties in code. Secondary tiles have two string properties, called TileId and Arguments. When a user launches your app from its secondary tile, the system passes these strings to your app’s OnLaunched method as members of the LaunchActivatedEventArgs parameter. The TileId identifies the secondary tile, and the Arguments property is a string with a maximum length of 2,048 characters that your app can use to distinguish further between a launch from a primary tile and a secondary tile.[65]

A cool feature of secondary tiles is that they are allowed to roam across all of a user’s machines. When creating a secondary tile, its RoamingEnabled property defaults to true. Now, if the user installs the app on another PC, the secondary tile will appear on the other PC’s Start screen automatically. Of course, this requires that the user log in to both PCs using her Microsoft account. Secondary tiles only roam on first installation. After this, the user can modify the secondary tiles independently on her PCs; this allows the user to have some secondary tiles on one PC but not on a different PC.

The call to RequestCreateAsync shows the user a dialog box like the one shown in Figure 8-6. From this dialog box, the user scrolls through the offered tile sizes and can edit the name displayed on the tile. Your app can also prompt the user to remove a secondary tile from the start screen by calling RequestDeleteAsync.

Secondary tile approval dialog box.

Figure 8-6. Secondary tile approval dialog box.

A user can unpin a tile from the Start screen at any time even if its app is not running. Later, when the app does run, it can determine if a particular secondary tile is still pinned by calling this method:

Boolean tileOnStartScreen = SecondaryTile.Exists(tileId);

And an app can discover all the secondary tiles it still has pinned on the Start screen by calling

IReadOnlyList<SecondaryTile> pinnedSecondaryTiles = await SecondaryTile.FindAllAsync();

Toast notifications

An app can pop up toast notifications that notify the user of some time-sensitive information. Examples include incoming calls, completion of a download, a printer running out of paper, and so on. Note that the app can always pop up a toast notification; the user does not have to be interacting with the app. Figure 8-7 shows what a toast notification looks like. (The small 30-pixel by 30-pixel logo is shown at the bottom right.) The user can ignore, dismiss, or tap the toast notification. Tapping the toast notification launches its app, bringing it to the foreground. Toast notifications can be accompanied by sound, and they can vary in duration and be tailored for different purposes, such as incoming calls or calendar reminders.[66]

Example of a toast notification on the desktop.

Figure 8-7. Example of a toast notification on the desktop.

As with tiles, the user is in control of toast notifications. By default, Windows allows toast notifications to display; however, the user can disable toasts for a specific app by going to the app’s Settings pane as shown in Figure 8-8.

An app’s Settings pane, allowing the user to disable the app’s toast notifications.

Figure 8-8. An app’s Settings pane, allowing the user to disable the app’s toast notifications.

Users can also manage toast notification settings for all their installed apps and for the system as a whole in PC Settings > Search And Apps > Notifications as Figure 8-9 shows.[67]

Controlling apps’ notifications from PC Settings.

Figure 8-9. Controlling apps’ notifications from PC Settings.

If you want your app to display toast notifications, you must first enable them in your app’s manifest: under the Application section, set Toast Capable to Yes. This is how Windows knows to add your app to the app’s permission settings pane and to the PC Settings Notifications pane.

The XML schema for toast notifications is similar to the one for tile notifications. You can find it here: http://msdn.microsoft.com/en-us/library/windows/apps/br230846.aspx. To see the catalog of toast templates, see http://msdn.microsoft.com/en-us/library/windows/apps/hh761494.aspx.

Here is how to create a toast notification:

ToastNotifier tn = ToastNotificationManager.CreateToastNotifier();
// If the user disabled our app's toast notifications, just return
if (tn.Setting != NotificationSetting.Enabled) return;
// Build the toast notification's XML template:
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(
   ToastTemplateType.ToastImageAndText01);
// Set image and text:
toastXml.GetElementsByTagName("image")[0].Attributes.GetNamedItem("src")
   .NodeValue = "ms-appx:///Assets/snowday.jpg";
toastXml.GetElementsByTagName("text")[0]
   .AppendChild(toastXml.CreateTextNode("This is a toast notification."));
// Set launch argument:
XmlAttribute launch = toastXml.CreateAttribute("launch");
launch.Value = "Launch argument goes here";
toastXml.GetElementsByTagName("toast")[0].Attributes.SetNamedItem(launch);
// Set duration:
XmlAttribute duration = toastXml.CreateAttribute("duration");
duration.Value = "long"; // or "short"
toastXml.GetElementsByTagName("toast")[0].Attributes.SetNamedItem(duration);
// Set audio sound:
XmlElement audio = toastXml.CreateElement("audio");
var audioA = toastXml.GetElementsByTagName("toast")[0].AppendChild(audio);
var audioSrc = toastXml.CreateAttribute("src");
audioSrc.Value = "ms-winsoundevent:Notification.Looping.Call";
audioA.Attributes.SetNamedItem(audioSrc);
var loop = toastXml.CreateAttribute("loop");
loop.Value = "true";
audioA.Attributes.SetNamedItem(loop);
// Pop up the toast notification
tn.Show(new ToastNotification(toastXml));

The XML toast template for this toast notification looks like this:

<toast launch="Launch parameters go here" duration="long">
   <visual>
      <binding template="ToastImageAndText01">
         <image id="1" src="ms-appx:///Assets/snowday.jpg"/>
         <text id="1">This is a toast notification.</text>
      </binding>
   </visual>
   <audio src="ms-winsoundevent:Notification.Looping.Call" loop="true"/>
</toast>

Once the system displays a toast notification, the user can ignore it, dismiss it, or activate it. Most apps only care about the user activating the toast so that the user can perform some action. When the user activates a toast, Windows activates its app and calls the virtual OnLaunched method, and the app can respond however it wants.

protected override void OnLaunched(LaunchActivatedEventArgs args) {
   // For a toast notification, args's TileId property equals
   // Windows.ApplicationModel.Core.CoreApplication.Id
   // Query args.Arguments for launch arguments set in XML ("Launch parameters go here")
   ...

Usually, an app will not display toast notifications if the app is in the foreground. Doing so is unnecessary because the app already has the user’s attention. However, ToastNotification does expose three events that an app can register callback methods with: Activated, Dismissed, and Failed.

When the user activates the toast, the system resumes your app (if suspended), raises the Activated event,[68] and then calls the OnLaunched method. When the user dismisses a toast, the system raises the Dismissed event if your app is running. If your app is not running, the Dismissed event is raised after the user resumes your app.[69] Additionally, your Dismissed event handler is passed a ToastDismissedEventArgs parameter indicating how the toast got dismissed (the user canceled it, the toast timed-out, or your app called ToastNotifier’s Hide method). Note that the system raises these events on non-GUI threads, so you must marshal to the GUI thread if you want to update the UI in response to these events. The system will not raise any of these events if your app is terminated; the system will just launch your app and call its OnLaunched method.

When preparing the XML toast template, you get to specify how long the toast should appear to the user before automatically dismissing itself. By default, toast notifications appear for a short duration of seven seconds; the alternative is a long duration of 25 seconds. Typically, you use short-duration toasts for simple notifications that don’t require the user to launch your app—for example, the arrival of new email or a social media update. On the other hand, long-duration toasts are more appropriate for events when someone else is waiting, such as when someone is initiating a chat message or there is an incoming phone call.

When displaying a toast notification, the system can also play a sound. To do this, you need to give the toast template an “audio” element. By default, this is a one-time sound, which is appropriate for short-duration toasts such as email notifications or appointment reminders. Although your app can’t specify its own custom sounds, you can choose from a predefined set of system sounds. Your app can also specify that the toast needs to play the audio in a loop (loop=true), which requires the toast’s duration to be long.

Showing a toast notification at a scheduled time

When your app is in the foreground, the usefulness of showing toast notifications is somewhat limited. The purpose of toasts notifications is to notify the user of something important happening in an app that is not in the foreground. For this, your app can show a toast from a background task that runs when certain events happen, such as logon or a network status change. (See Chapter 9.) Additionally, your app can schedule a toast to pop up at a very specific time—for example, an appointment reminder. Here’s how to schedule a toast to display one hour from when the code executes:

ScheduledToastNotification scheduledToastNotification = new ScheduledToastNotification(toastXml,
   DateTimeOffset.UtcNow.AddHours(1),  // Delivery time
   TimeSpan.FromMinutes(1),               // Snooze interval (minimum=1 minute)
   2) { Id = "Meeting" };                 // Max display count & ID
tn.AddToSchedule(scheduledToastNotification);

We also set a snooze interval that tells the system to show the toast again if the user ignores or dismisses the toast notification. With the recurrence setting of 2, the toast will actually appear three times. You can use the ToastNotifier to iterate through the scheduled toasts and remove them from the schedule if they are no longer applicable.

Because it is unlikely that your app will be running when the scheduled toast comes up, the system does not support the Activated, Dismissed, and Failed events for scheduled toasts. When the user taps a scheduled toast, the system calls OnLaunched regardless of whether your app was running, suspended, or terminated.

Using the Wintellect Notification Extension Library

Working with the raw XML to create your tile, badge, and toast notifications can become tedious. The code that accompanies this book has a library to help you focus on the notifications instead of the XML.[70] The library gives you type-safety and IntelliSense support. Using the library, the code to produce the XML toast template shown in the previous section looks like this:

var toastXml = new Wintellect.WinRT.Notifications.ToastTemplate(
   ToastTemplateType.ToastImageAndText01) {
   Images = { "ms-appx:///Assets/snowday.jpg" },
   Text = { "This is a toast notification." },
   Launch = "Launch argument goes here",
   Audio = new ToastAudio { Loop = true, Source = SoundEvent.LoopingCall },
   Duration = ToastDuration.Long,
};

Additionally, the library also checks whether images exist at the specified URLs and that they are in a supported format and size. If a violation is discovered, the library throws an exception right away, greatly improving your debugging experience.

Windows Push Notification Service (WNS)

Table 8-1 listed four ways to update tiles, badges, and toast notifications. In this section, we focus on the last technique, Windows Push Notification Service (WNS).

Periodic updates with URLs go a long way in updating your app’s tiles and badges, especially because you can personalize the notifications by using query strings. I already mentioned providing a ZIP code for weather apps. You also can provide a list of stock symbols to adjust the tile to the user’s preferences, and so on. Periodic updates suffer from their resolution; they can update no quicker than once every 30 minutes. For some scenarios, you want to notify the user immediately that something has occurred. Examples include flight updates, incoming messages, social updates, and investment changes. WNS sends real-time tile, badge, or toast notifications to a specific user on a specific PC. Whereas periodic updates use a polling mechanism, WNS allows you to push a notification to a user/machine when you need to. Because WNS doesn’t waste network bandwidth or CPU cycles for potentially unfruitful requests, it is more efficient than polling. This is great news for both your user’s battery as well as his network bandwidth.

In addition to tiles, badges, and toast notifications, WNS can also send a raw string to a background task (or to your app if it happens to be running). Your app subscribes to these raw notifications, and because a raw string is an app-defined string payload, your server can send whatever it wants. You’ll learn about this more in Chapter 9.

You can see the flow of events for WNS in Figure 8-10. The architecture consists of three pieces: Windows and your app, WNS, and your app’s web service. At a high level, here are the workflow steps you need to perform to push notifications from your app’s web service to your app on a user’s PC:

  1. Your app registers itself and the user’s PC with WNS; WNS returns a unique-channel URI.

  2. Your app then sends this channel URI to your app’s web service. Typically, you save all your user’s channel URIs in a database of some sort.

  3. When your app’s web service wants to notify a user of something, it looks up the user’s channel URI from the database and sends the desired tile, badge, toast, or raw notification to WNS.

  4. WNS then pushes the notification down to the user’s PC, which then updates the tile or badge, displays a toast, or invokes your app’s background task.

Windows Push Notification Service workflow.

Figure 8-10. Windows Push Notification Service workflow.

Registering your app and the user’s PC with WNS

Your app registers itself and the user’s PC with WNS as follows:

PushNotificationChannel channel =
   await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
// channel has 2 properties: Uri and ExpirationTime

Also, multiple calls to CreatePushNotificationChannelForApplicationAsync return the same channel URI. Channel URIs expire every 30 days or so. (PushNotificationChannel’s ExpirationTime property returns the channel’s expiration time.) So your app will have to periodically renew its channel URI and send the latest URI to your app’s web service. The best way to accomplish this is to create a maintenance background task that runs every 25 days or so. (See Chapter 9.)

To update a secondary tile’s content or badge, get a channel URI by calling PushNotificationChannelManager’s CreatePushNotificationChannelForSecondaryTileAsync method. Because users can unpin secondary tiles from the Start screen at any time, you should renew their channel URIs only if they are still present on the Start screen. A typical channel URI looks like this (truncated):

https://db3.notify.windows.com/?token=AQI8iP%2OtQE%3d...

Note that the format of the channel URI is an implementation detail, and there is no need for you to examine or parse it; just send it to your service. As you can deduce from the channel URI string, the WNS client opens a secure connection to notify.windows.com. This connection needs to remain open so that WNS can push notifications. It also means that the firewall on the user’s PC and potentially the proxy server have to allow HTTPS communication to windows.com.

If your app is running when WNS pushes a notification, your app can intercept the notification, execute some code in response, and even cancel the notification if it desires. Your app intercepts a pushed WNS notification by registering an event handler with PushNotificationChannel’s PushNotificationReceived event:

channel.PushNotificationReceived += PushNotificationReceived;

In the event handler, the system passes you the notification as a property of the PushNotificationReceivedEventArgs argument. Your callback can tell the system to ignore the notification by setting the Cancel property to true:

void PushNotificationReceived(PushNotificationChannel sender,
   PushNotificationReceivedEventArgs e) {
   XmlDocument xml = null;
   switch (e.NotificationType) {
      case PushNotificationType.Tile:  xml      = e.TileNotification.Content;  break;
      case PushNotificationType.Badge: xml      = e.BadgeNotification.Content; break;
      case PushNotificationType.Toast: xml      = e.ToastNotification.Content; break;
      case PushNotificationType.Raw:   String s = e.RawNotification.Content;   break;
   }
   // e.Cancel = true;  // If true (default=false), notification ignored
}

An app can call PushNotificationChannel’s Close method to invalidate the channel. This prevents all future notifications from being delivered to the app. It also prevents any tile, badge, toast, or raw notifications from being processed on the PC.

Send the channel URI to your app’s web service

Once your app has a channel URI, it needs to send it and its expiration time to your app’s web service. The web service is responsible for storing this information and any other information you might need to associate it with the specific user. The service uses this channel to periodically push notifications to the user’s PC. The web service should automatically purge any expired channel URIs; avoid pushing notifications to an expired channel URI via WNS.

WNS does not give your app infinite bandwidth to push notifications. WNS has a quota per app that is not documented. WNS returns HTTP 404 (not found) or 410 (gone [channel expired]) errors when channel URIs you send it are no longer valid; your app’s web service should remove these from its database and no longer attempt to use them. Unless you’re sure it makes sense for your scenario, the app’s web service should avoid retrying POSTs to WNS.

To prevent anyone from pushing notifications to your app, you must register your app with the WNS service. You configure your app to use WNS using the Windows Store Dashboard on Microsoft’s Dev Center site (http://dev.windows.com/).[71] First, you need to reserve an app name in the Windows Store (as discussed in Chapter 11). Then, from Visual Studio, associate your app with the reserved name using Project menu > Store > Associate App With The Store. The wizard sets your Store-assigned package identity name and publisher in your app’s manifest file. Alternatively, you can use the dashboard to show this information and then you can edit the manifest XML file yourself.

The Windows Store creates a Package Security ID (SID) and Client secret for your package. Your app’s web service must authenticate with WNS using these credentials. You get these values by going to your app in the Windows Store dashboard, clicking Services > Live Services Site > Authenticating Your Service. The values will look similar to these:

Package Security Identifier (SID)
ms-app://s-1-15-2-84216977-2665019123-2024476369-118581892-194604365-2052745452-3234447176
Client secret
6Tbbo0Hv1mQVIXbm7r/X+Q4PVH9IbxYl

You need these values in the next step to authenticate your app’s web service with WNS.

Pushing a notification from your app’s web service to the user’s PC

To push a notification, your app’s web service will first have to authenticate with WNS, which will return an OAuth token. The following code demonstrates how to do this:

[DataContract]
private sealed class OAuthToken {
   [DataMember(Name = "access_token")]
   public string AccessToken { get; set; }
   [DataMember(Name = "token_type")]
   public string TokenType { get; set; }
}
private async Task<OAuthToken> GetAuthenticationTokenAsync(
   String packageSid, String clientSecret) {
   var content = new Windows.Web.Http.HttpFormUrlEncodedContent(
      new Dictionary<String, String> {
         { "grant_type", "client_credentials"},
         { "client_id", packageSid },
         { "client_secret", clientSecret},
         { "scope", "notify.windows.com"}
      });
   using (var response =
      await new HttpClient()
         .PostAsync(new Uri("https://login.live.com/accesstoken.srf"), content)
         .AsTask().ConfigureAwait(false)) {
      return (OAuthToken)new DataContractJsonSerializer(typeof(OAuthToken))
         .ReadObject((await response.Content.ReadAsInputStreamAsync()
            .AsTask().ConfigureAwait(false)).AsStreamForRead());
   }
}

WNS returns an OAuth token in JSON format, which the previous code deserializes into an OAuthToken object. The OAuth token (in JSON) looks like this (truncated):

{"token_type":"bearer","access_token":"EgAbAQMAAAAEgAAACoAAJp33aucvS9...==","expires_in":86400}

You can then use the OAuthToken to build the HTTPS POST message:

public async Task<HttpResponseMessage> PushAsync(
   Byte[] payload, String channelUri, OAuthToken token) {
   var msg = new HttpRequestMessage(HttpMethod.Post, new Uri(channelUri));
   // Set mandatory information:
   msg.Headers.Authorization = new HttpCredentialsHeaderValue("Bearer", token.AccessToken);
   msg.Content = new HttpBufferContent(payload.AsBuffer());
   msg.Headers.Add("X-WNS-Type", "wns/tile"); // tile, badge, toast, or raw
   // For "wns/raw", the content type must be "application/octet-stream"
   msg.Content.Headers.ContentType = new HttpMediaTypeHeaderValue("text/xml");
   // Set optional headers:
   msg.Headers.Add("X-WNS-Cache-Policy", "cache");
   msg.Headers.Add("X-WNS-TTL", "60");  // Seconds
   // Assign tag label (max 16 chars) to notification; used by device to detect dups.
   msg.Headers.Add("X-WNS-Tag", "SomeTag");
   // Request for Device Status and Notification Status to be returned in the response
   msg.Headers.Add("X-WNS-RequestForStatus", "true");
   return await new HttpClient().SendRequestAsync(msg).AsTask().ConfigureAwait(false);
}

You need to add an X-WNS-Type header to indicate the type via four values: wns/tile, wins/toast, wns/badge, and wns/raw. You also have to add an Authorization string with the OAuth access token acquired from login.live.com. The last four headers are optional. X-WNS-Tag is the tag we used previously to target specific tiles in the notification queue. Similarly, X-WNS-TTL indicates (in seconds) how long the notification should live before it automatically expires. The cache value indicates what WNS needs to do with a notification if the target machine is offline. The default is to cache one badge and one tile notification, unless your app has tile queuing enabled—in which case, WNS caches up to five tile notifications. The last optional header, X-WNS-RequestForStatus, tells WNS that our web service wants to know the status of the user’s PC.

If you set the X-WNS-RequestForStatus request header to true, you get additional information back in the response:

X-WNS-NOTIFICATIONSTATUS: received
X-WNS-DEVICECONNECTIONSTATUS: connected
X-WNS-MSG-ID: 354223800B2B76E6
X-WNS-DEBUG-TRACE: BN1WNS1011529
Content-Length: 0
Date: Mon, 08 Oct 2012 20:05:14 GMT

The X-WNS-NOTIFICATIONSTATUS response header indicates that WNS has received the notification. If the end user has turned off notifications, this has a status of “dropped.” Your app can also exceed the bandwidth of the channel—in which case, the status will be “channelthrottled.” WNS returns X-WNS-DEVICECONNECTIONSTATUS if your app’s web service asked for it in the request by specifying X-WNS-RequestForStatus. The X-WNS-MSG-ID and the X-WNS-DEBUG-TRACE are used for debugging purposes when you need to ask Microsoft support to trace WNS messages.

To help debug WNS failures, see the following location in the system’s event log:

Applications And Services Log > Microsoft > Windows > PushNotifications-Platform

In addition, you (and your users) can see how much network usage an app is consuming for tiles and notifications by using Task Manager’s Tile Updates column (as shown in Figure 8-11).

Task Manager’s Tile Updates column shows network bandwidth used for an app’s tiles and notifications.

Figure 8-11. Task Manager’s Tile Updates column shows network bandwidth used for an app’s tiles and notifications.



[63] Enter semantic zoom mode by pinching your fingers together, using Ctrl+Mouse wheel, or using Ctrl+Plus Sign or Ctrl+Minus Sign.

[64] If you need more control over your tile’s content, create an image file containing any content you want and then have your tile show this image file.

[65] When the user launches your app via its primary tile, the TileId property will be set to a value defined in your app’s manifest-specifically, the Application element’s Id attribute. Usually, this has a value of “App”. At runtime, your app can get this value by querying the Windows.ApplicationModel.Core.CoreApplication.Id property.

[66] Desktop apps can use WinRT APIs to show toast notifications as well. See the sample at http://code.msdn.microsoft.com/windowsdesktop/sending-toast-notifications-71e230a2/.

[67] The Settings charm and Control Panel say Notifications, but this setting applies only to toast notifications. Tile and badge notifications are unaffected.

[68] The Activated event’s signature indicates that it passes a ToastNotification and Object; however, you can cast the second argument to a ToastActivatedEventArgs and query its Arguments property to see which ToastNotification was activated.

[69] Interestingly, the system raises the Dismissed event before the Resuming event. Thus, you need to be careful with assumptions about the state of your app if it does anything in the Resuming event handler.

[70] Microsoft also has the NotificationsExtensions library. For more information, see http://msdn.microsoft.com/en-us/library/windows/apps/Hh969156.aspx.

[71] This means that you can’t use WNS for apps that are not in the store, such as enterprise side-loaded apps.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.167.87