Chapter 13
Tiles, Notifications, the Lock Screen, and Background Tasks

At the risk of seriously dating myself once again, I can still remember how a friend and I marveled when we first acquired modems that allowed us to do an online chat. At that time the modems ran at a whopping 300 baud (not Kb, not Mb—just b) and we connected by one of us calling the other’s phone number directly. It would have been far more efficient for us to just talk over the phone lines we were tying up with our bitstreams! Such was the early days of the kind of connectivity we enjoy today, where millions of services are ready to provide us with just about any kind of information we seek with transfer speeds that once challenged the limits of believability.

Even so, almost from the genesis of online services it’s been necessary to enter some kind of app, be it a client app or a web app, to view that information and get updates. When computers could run only a single app at a time (like the one I was using with that 300 baud modem60), this could become quite cumbersome, and it made it difficult, if not impossible, to take data from one program and transfer it to another. With the advent of multitasking operating systems like Windows, you could run such apps side-by-side and transfer information between them, a model that has stuck with us for several decades now. Even many web apps, for the most part, still operate this way. There have been innovations in this space, certainly, such as mashups that bring disparate information together into a more convenient place, but such an experience is still hidden within an app.

That changes with Windows 8. As one columnist recently put it, “Using Windows 8 is like living in a house made out of Internet…The Start screen is a brilliant innovation, [a] huge improvement on the folder-littered desktops on every other OS, which serve exactly no purpose except to show a background photo. The Start screen makes it possible to check a dozen things”—if not more, I might add!—“in five seconds—from any app, just tap the Windows key and you can check to see if you have a new email, an upcoming appointment, inclement weather, or any breaking news. Tap the Windows key again and you’re back to your original app.”61 He goes on to suggest how long this would take if you had to go into individual apps to check the same information, even with high-speed broadband!

What makes the Start screen come alive in this way are what we call live tiles, Microsoft’s answer to the need to bring information from many sources together at the core of the user experience, an experience that “is constantly changing and updating,” as the same writer puts it, “because its every fiber is connected to the Internet.” With live tiles, each one is a small window onto whatever wealth of information an app is built around; the app is essentially extracting the most important pieces of that information according to each user’s particular interests. And as the user adds more apps to the system—which adds more tiles to the Start screen that the user can rearrange and group however he or she likes—the whole information experience becomes richer.

Even so, live tiles and the Start screen are just the beginning of the story. It’s ironic that this chapter has one of the longest titles in the entire book, listing off four things that do not, at first glance, appear to be related: tiles, notifications, the lock screen, and background tasks. Maybe you’re just thinking that I couldn’t figure out where else to put them all! In truth, however, they together form what is essentially a single topic: how apps work with Windows 8 to create an environment that is alive with activity while those apps are often not actually running or are allowed to run just a little bit.

Let’s begin, then, by exploring those relationships and the general means through which apps wire their tiles and other notifications to their information sources.

Before going further Refer back to the section named “Systemwide Enabling and Disabling of Animations” early in Chapter 11, “Purposeful Animations,” and check your Control Panel setting. If “unnecessary” animations are turned off, live tiles won’t be animated and you won’t see the complete experience they can provide.

Second, because all the topics of this chapter are related to one another, various aspects that I’ll discuss in one section of this chapter—in the context of tiles, for example—also apply to other sections—such as toast notifications. For this reason it is best to read this chapter from start to finish.

Third, many aspects of what we cover in this chapter are not enabled within the Windows Simulator, such as live tiles, toast notifications, and the lock screen. When running some of the samples within Visual Studio, be sure to use the Local Machine or Remote Machine debugging options.

Finally, the tile and notifications API is generally found within Windows.UI.Notifications, which is a lot to spell out every time. Unless noted, assume that the WinRT APIs we’re talking about come from that namespace.

Alive with Activity: A Visual Tour

When an app is first acquired from the Windows Store and installed on a device, its primary app tile is, as we know well already, added to the Start screen. These tiles can be square or wide, depending on what graphics the app provides in its package. If an app provides both a square and wide graphic, the user can, as shown in Figure 13-1, use an app bar command to change the width.

Images

FIGURE 13-1 The typical default Start screen with the built-in apps and the app bar showing the command (third from left) to make a wide tile smaller, into a square tile. The same command on a square tile might appear as Larger (see overlay) if the app supports wide tiles.

When you first installed Windows 8 on a device, you might not have noticed that the Start screen was somewhat quiet, tiles for a few built-in apps (like Weather, News, and Bing) were updating, but most of them were static. But as soon as you ran some of those apps—which I imagine you did within a couple of seconds!—the Start screen suddenly lit up much more, with many tiles changing every few seconds as I attempt to show in Figures 13-2 and 13-3. This is because apps need to be run once to make their initial connections to their associated web services and enable their live tiles62.

Images

FIGURE 13-2 A Start screen after running most of the built-in apps and taking some initial configuration steps, such as connecting the People app to my Facebook account.

Images

FIGURE 13-3 The same Start screen a few seconds later after a number of apps have updated their tiles.

What can appear on any given tile is quite extensive and varied. As you can see in the previous figures, square and wide tiles can display text, images, an app name or logo (at the lower left), and other small glyphs or numbers called badges at the lower right (on the Mail and Store tiles in Figure 13-3, for example).

Selecting an item on the Start screen also invokes the app bar, shown in Figure 13-4, which offers commands to unpin a tile from the Start screen, uninstall the app, change the tile size (as we’ve seen), and turn off updates for a particular live tile.

Images

FIGURE 13-4 The app bar for the Start screen when a tile is selected. The Turn Live Tile Off command will disable updates for a given tile, so be careful not to annoy your customers with too much noise!

Tiles can receive updates even when the app isn’t running, as we’ll see in the next section, “The Four Sources of Updates and Notifications.” Tiles can also cycle through up to five updates, an important feature that reduces the overall number of updates that actually need to be retrieved from the Internet (thus using less power). That is, by cycling through different updates a tile will continue to appear alive even though it is only receiving new updates in a timeframe of 5–15 minutes instead of 5–15 seconds.

Tip Even though live tiles can be updated frequently through push notifications, be careful not to abuse that right. Think of live tiles as views into app content rather than gadgets: avoid trying to make a live tile an app experience unto itself (like a clock) because you cannot rely on high-frequency updates. Furthermore, a tile update consists only of XML that defines the tile content—updates cannot trigger the execution of any code. In the end, think about the real experience you want to deliver through your live tile and use the longest update period you can that will still achieve that goal.

In the introduction I mentioned how acquiring more apps from the Windows Store is a way that the Start screen becomes increasingly richer. But new apps are not the only way that more tiles might appear. Apps can also create secondary tiles with all the capabilities of the app tile. Secondary tiles are essentially ways to create bookmarks into views of an app. A secondary tile is typically created through a Pin command on the app bar. Upon the app’s request to create the tile, Windows automatically prompts the user for confirmation as shown for the Weather app in Figure 13-5, thus always keeping the user in control of their Start screen (that is, apps cannot become litterbugs on that real estate!). In this case the Weather app lets you pin secondary tiles for each location you’ve configured; the secondary tile always includes specific information that is given back to the app when it’s launched, allowing it to navigate to the appropriate page.

Images

FIGURE 13-5 Pinning a secondary tile in the Weather app by using a Pin To Start app bar command, shown here with the automatic confirmation prompt.

In the People app, similarly, you can pin—that is, create secondary tiles for—specific individuals. In the Mail app you can pin different accounts and folders. In Internet Explorer you can pin your favorite websites. You get the idea: secondary tiles let you populate the Start screen with very personalized views into different apps. The user can also unpin any app tile at any time (including the primary app tile, as can happen when one has created a number of secondary tiles for more specific views). An app can ask to unpin a tile as well, in response to which Windows will again prompt the user for confirmation.

User tip You probably know that you can drag and drop tiles around on the Start screen into different sections. But did you also know that you can create group headers for those sections? To do this, do a semantic zoom out on the Start screen (a pinch gesture, Ctrl+mouse wheel down, or the Ctrl+minus key), select a group, and then invoke the Name Group command on the app bar:

Images

In many ways, live tiles might reduce the need for a user to ever launch the app that’s associated with a tile. Yet this isn’t really the case. Because tiles are limited in size and must adhere to predefined configurations (templates), they simultaneously provide essential details while serving as teasers. They give you enough useful information for an at-a-glance view but not so much that your appetite for details is fully satisfied. Instead of being a deterrent to starting apps, they’re actually an invitation: they both inform and engage. For this reason, I suspect that live tiles will be considered an essential app feature where they are appropriate and that apps that should provide them but don’t will see lower ratings in the Windows Store.

I encourage you to be creative in thinking about what kinds of interesting information you might surface on a tile, even if your app doesn’t have anything to do with the Internet. Games, for example, can cycle through tile updates that show progress on various levels, high scores, new challenges, and so forth—all of which invite the user to re-engage with that app. Do remember, though, that the user can always disable updates for any given tile, so don’t give them a reason to defeat your purpose altogether!

As additional background on live tiles, check out the Updating live tiles without draining your battery post on the Building Windows 8 blog. It’s good background on the system’s view of efficiently managing tiles.

Now, for all the excellence of live tiles, the Start screen isn’t actually where users will be spending the majority of their time—we expect them, of course, to mostly be engaged in apps themselves. Even so, users may want to be notified when important events occur, such as the arrival of an email, the triggering of an alarm, or perhaps a change in traffic conditions that indicates a good time to head home for the day (or a change in weather conditions that indicates a great time to go out skiing!).

For this purpose—surfacing typically time-sensitive information from apps that aren’t in the foreground—Windows 8 provides toast notifications. These transient messages pop up (like real toast but without the bread crumbs) in the upper right corner of the screen (upper left in right-to-left languages). They appear on top of the foreground app as shown in Figure 13-6, as well as the Start screen and the desktop. Up to three toasts can appear at any one time, and each can be accompanied by a predefined sound, if desired.

Toasts are, like tile updates, created using predefined templates and can be composed of images, text, and logos; they always use the originating app’s color scheme, as defined in that app’s manifest (the foreground text and Background color settings in the Application UI section).

The purpose of toasts is, again, to give the user alerts and other time-sensitive information, but by default they appear only for a short time before disappearing. The default toast duration is five seconds, but this can be set to as long as five minutes in PC Settings > Ease of Access, as shown in Figure 13-7. Apps can create long-duration toasts that remain visible for 25 seconds or the Ease of Access setting, whichever is longer. Furthermore, apps can create a looping toast for events like a phone call or other situation where another human being might be waiting on the other end and it’s appropriate to keep the notification active for some time.

Images

FIGURE 13-6 Up to three toast notifications can appear on top of the foreground app (including the desktop and the Start screen). Each notification can also play one of a small number of predefined sounds.

Images

FIGURE 13-7 Toast duration settings (a drop-down list) in PC Settings > Ease of Access.

As with tile updates, the user has complete control over toast notifications: for the entire system, for the lock screen, and for individual apps. Users do this through PC Settings > Notifications, as shown in Figure 13-8. This ultimately means that you want to make your notifications valuable to the user; if you toss up lots of superfluous toast, chances are that the user will turn them off for your app or for the whole system (and give you bad reviews in the Windows Store).

Images

FIGURE 13-8 The user can exercise fine control over notifications in PC Settings > Notifications.

As with secondary tiles, each toast notification contains specific data that is given to its associated app when it’s activated. If the app is suspended, of course, Windows switches to that app and fires its activated event with the notification data. If the app isn’t running, Windows will launch it. (The Win+V key, by the way, will cycle the keyboard focus through active toasts, such that pressing Enter will activate it.)

This brings up the point that toast notifications, like tile updates, can originate from sources other than a running app—which should be obvious because nonforeground apps will typically be suspended! Again, we’ll talk about those sources in the next section. At the same time, you might be wondering if the last item in this chapter’s title—background tasks—comes into play here.

Indeed it does! As we’ve already seen with background audio apps in Chapter 10, “Media,” it’s not a hard-and-fast rule that apps are always suspended in the background.63 It’s just that Windows, on its quest to optimize battery life, doesn’t allow arbitrary apps to keep themselves running for arbitrary reasons. Instead, Windows allows apps to run focused background tasks for specific purposes—called triggers—subject to specific quotas on CPU time and network I/O. As you might expect, an app declares such background tasks in its manifest.

Triggers include a change in network connectivity, a time zone change, an update of an app, the expiration of a timer (with a 15-minute resolution), or the arrival of a push notification from an online source (that is, a notification sent in response to a condition that’s completely external to the device itself). Each trigger can also be configured with conditions such as whether there is Internet connectivity or not. Whatever the case, the whole purpose of background tasks is not to launch an app—in fact, background tasks cannot display arbitrary UI. It is rather to allow them to update their internal state and, when needed, issue tile updates or toast notifications through which the user can make the choice to activate the app for further action.

One additional aspect of background tasks is that Windows also places a limit on the total number of apps that can handle certain kinds of triggers: timers, receipt of push notifications, and receipt of network traffic on a control channel as used by real-time communications apps. The limit is imposed by the fact that such apps must be added to the lock screen for their tasks to run at all.

The lock screen, as you certainly know by now and as shown in Figure 13-9, is what’s displayed anytime the user must log into the device. A device will be locked directly by the user or after a period of inactivity. An exception is made when an app has disabled auto-locking through the Windows.-System.Display.DisplayRequest API, as discussed in Chapter 10 in the “Disabling Screen Savers and the Lock Screen During Playback” section.

Images

FIGURE 13-9 A typical lock screen. Up to seven apps can display badges along the bottom of the screen; one app can display text next to the clock.

Yet Windows doesn’t want to force the user to log in just to see the most important information from their most important apps. Through PC Settings, as shown in Figure 13-10, the user can add up to seven apps to the lock screen (provided those apps have requested access, which is subject to user consent). These apps must be registered for lock screen–related background tasks during which they can issue badge updates to the lock screen—these are what you see above along the bottom of Figure 13-9, where each badge glyph (the numbers) is also accompanied by a monochrome graphic, referred to as the Badge Logo in the app manifest. This graphic is 24x24 at 100%, 33x33 at 140%, and 43x43 at 180%, and it must contain only white or transparent pixels.

In addition, the user can indicate a single app that can display a piece of text (but not an image) next to the clock. Note that toast notifications raised by these apps will surface on the lock screen; if tapped, the lock screen will bounce and the app will be activated once the user signs in.

Images

FIGURE 13-10 Configuring the lock screen and lock screen apps in PC Settings.

Thus we complete the story of how Windows 8 works with apps to be alive with activity—on the Start screen, on the lock screen, and while the user is engaged in other apps—while yet conserving battery power by intelligently managing how and when apps can issue their various updates. Let’s now see exactly how that’s accomplished, ideally without needing apps to run at all.

The Four Sources of Updates and Notifications

When an app is active in the foreground, it can clearly issue whatever notifications it wants: updates to any of its tiles, badge updates, and toast notifications. Together these are simply referred to as local updates because they originate from the running app and are applied immediately, as shown in Figure 13-11.64 A running news app, as an example, might issue up to five updates to its tiles so that recent headlines continue to cycle when the user switches to another app. Such updates can also be set to expire at some date and time in the future so that they’ll disappear automatically (perhaps fulfilling the adage, “No news is good news”!). With toasts, note that a foreground app should use inline messages, flyouts, and message dialogs for errors that pertain to the currently visible content; toasts are only appropriate for alerts about content in some other part of the app.

Images

FIGURE 13-11 Local updates from a running app are applied immediately.

The second source of updates are scheduled notifications that apply to tile updates and toasts. A running app issues these to the system with the date and time when the update or notification should appear, regardless of whether the app will be running, suspended, or not running at that future time. This is illustrated in Figure 13-12. A calendar app, for example, would typically use scheduled notifications for appointment reminders.

Images

FIGURE 13-12 Scheduled notifications are managed by the system and will appear at the requested time irrespective of the state of the originating app.

The third way an app can issue updates—in this case for tiles and badges only—is through a periodic update. As illustrated in Figure 13-13, a running app configures the system’s tile and badge updaters to request an update from a specific web service URI at certain low-frequency intervals (the minimum is 30 minutes) beginning at a specified time, if desired. The web service responds to this HTTP request with an XML payload that’s equivalent to what a running app would provide in a local update, and updates can be set with an expiration date/time so that they’re automatically removed from the update cycle when appropriate. With all these capabilities, periodic updates are wholly sufficient for many apps to create very dynamic live tiles with relatively little effort.

Images

FIGURE 13-13 Periodic updates for tiles and badges are registered with the system’s tile updater, which will request an update from a web service at regular intervals.

Of course, a 30-minute minimum interval is simply not fast enough when an app wants to notify a user as soon as possible. Thus we have the fourth means for updates—push notifications—and this method applies across tiles and toasts, as well as non-UI (raw) notifications.

Push notifications are, as the name implies, sent directly to a device not at the request of an app but at the request of some associated web service that is typically monitoring information or other conditions around the clock. As illustrated in Figure 13-14, that web service employs the free Windows Push Notification Service (WNS for short) to send notifications to those apps that have created a channel for this purpose. Each channel is specific to a user and the device. As with other updates, this requires the app to be run at least once, because it’s during that first launch that the app establishes a WNS channel for the given device.

A push notification can contain an XML payload as with other tile updates and toast notifications, but it can also be used to send a non-UI raw notification that contains arbitrary data. A raw notification must be received by a running app or a by lock screen app with a background task for with the push notification trigger—otherwise the system clearly won’t know what to do with it!

Images

FIGURE 13-14 Push notifications originate with an always-running web service and are then sent to the Windows Push Notification Service for delivery to specific clients (a specific app on a specific user device) through their registered WNS channels.

A helpful summary of these different update mechanisms can be found on Choosing a notification delivery method in the documentation, a topic that includes various examples of when you might use each method. Whatever the case, we’re now ready to see the details of how we employ all of them in an app to help keep a system alive with activity.

Tiles, Secondary Tiles, and Badges

The very first thing you should know about your app tile is that if you want to enable live wide tiles (including secondary ones), you must include a wide logo image in the Application UI section of your manifest as shown below. Without it, you can still have live square tiles, but wide tile updates will be ignored.

Images

At this point I encourage you to go back to Chapter 3, “App Anatomy and Page Navigation,” and review the “Branding Your App 101” section where we discuss how different bits in the manifest affect your tiles, such as the Short Name and Show Name settings. As also covered in that section, remember to provide different scaled versions of your logo and wide logo images. Even though you might issue tile updates as soon as your app is run, your static tiles will be essential to the user’s first impression of your app after it’s acquired from the Windows Store. The static tiles are also what the user will see if he or she turns your live tiles off or if all your updates expire. So, even if you plan for live tiles, be sure to still invest in great static tile designs as well.

Providing both square and wide static tiles enables you to issue live tile updates to both, including square and wide secondary tiles. In both cases, try to think through what the user would most want to see. When users select a wide tile, which is to say they’re electing to have your tile occupy more prime real estate on the Start screen, it’s likely that they’re looking for details that add value to the Start screen. If users choose a square tile, on the other hand, they’re probably more interested in only the most essential information: the number of new email messages (as expressed through a badge), for example, rather than the first line of those messages, or the current temperature in a location rather than a more extended forecast.

The Guidelines and checklist for tiles and badges provides rather extensive guidance on this particular topic along with appropriate use of logos, names, badges, and updates. There is also a helpful post on the Windows 8 Developer Blog called Creating a great tile experience. Here we’ll concern ourselves with how such updates and badges are sent to a tile, a process that involves what are called tile XML templates, predefined XML configurations that you populate with text, images, and other properties. These templates apply to all forms of tiles and update methods, which we’ll examine in a moment. First, however, let’s see how secondary tiles are managed because everything we talk about thereafter applies equally to all tiles for the app.

Note The tile and notifications API is generally found within Windows.UI.Notifications, except those for creating secondary tiles that come from Windows.UI.StartScreen. Unless otherwise noted, assume that the APIs we’re talking about come from that namespace. That way we don’t have to spell it out every time!

Secondary Tiles

A secondary tile is a kind of bookmark into an app, to achieve what’s also called deep linking: a way to launch an app into a particular state or to a particular page. Secondary tiles allow the user to personalize the Start screen with more specific views of an app. As suggested on Guidelines and checklist for secondary tiles (a topic I highly recommend you read), offering the ability to create a secondary tile is a good idea whenever you have app state that could be a useful target or destination unto itself. Don’t create secondary tiles, however, for static content or use them as virtual command buttons—that would only educate your customers that they shouldn’t bother to pin tiles from your app!

An app creates a secondary tile in response to a Pin command that it typically includes on its app bar (using the WinJS.UI.AppBarIcon.pin icon). Offer this command when the app is displaying pinnable content or the user has made an appropriately pinnable selection; hide or disable the command if the content or selection is not pinnable. In addition, change it to an Unpin command if the content is already pinned. For details on managing commands in the app bar, refer to Chapter 7, “Commanding UI.”

When the Pin command is invoked, the app makes the request to create the tile. Windows then prompts the user for their consent, as shown earlier in Figure 13-5.

Once created, a secondary tile has all the same capabilities as your app tile, including the ability to receive updates from any source. They key difference between the app tile and secondary tiles is that the former launches the app into its default (or current) state, whereas the latter launches the app with specific arguments that your activation handler uses to launch (or activate) the app into a specific state. Let’s see how it all works.

Creating Secondary Tiles

The process for creating a secondary tile in response to a pin command is quite simple: first create an instance of Windows.UI.StartScreen.SecondaryTile with the desired options, and then call either its requestCreateAsync or requestCreateForSelectionAsync method. If the user confirms the creation of the tile, it will be added to the Start screen and your completed handler will receive a result argument of true. If the user dismisses the flyout (by tapping outside it), the comple-ted handler will be called with a result argument of false. The error handler for these methods will be called if there is an exception, as if you fail to provide required properties in the SecondaryTile.

When creating a SecondaryTile object, you can use four different constructors:

SecondaryTile() Creates a SecondaryTile with default properties.

SecondaryTile(tileId) Initializes the SecondaryTile with a specific ID, typically used when creating an object before an update or when unpinning the file.

SecondaryTile(tileId, shortName, displayName, arguments, tileOptions, logo) Creates a SecondaryTile with all the required properties for a square tile.

SecondaryTile(tileId, shortName, displayName, arguments, tileOptions, logo, wideLogo) Creates a SecondaryTile with all the required properties for a wide tile.

These options clearly correspond to the following SecondaryTile properties, all of which are required when you call a requestCreate* method (except wideLogo that is only required for a wide tile):

tileId A unique string (a maximum of 64 alphanumeric characters including . and _) that identifies the tile within the package. You need this when you want to update or delete a tile, and it should always be set. This value is typically derived from the content related to the file. If you create secondary tiles with a tileId that already exists, the new one will takes its place.

shortName The text string (40 characters max) that initializes the contents of the tile name control, as shown earlier in Figure 13-5. This is displayed directly on the tile but can be modified by the user before the tile is actually created. Once the tile is created, this value will contain the string as it appears on the tile.

displayName The tile’s display name that will be shown in the tile’s tooltip, next to the app in the Start screen’s All Tiles list, and a few other areas within Windows. This can be whatever length you want and can contain any characters.

arguments A string that’s passed to the apps activation handler when the secondary tile is invoked.

tileOptions One or more values from the TileOptions enumeration, combined with the | (bitwise OR) operator. Options include none (the default), showNameOnLogo (displays shortName on the square tile), showNameOnWideLogo (displays shortName on the wide tile), and copyOnDeployment (indicates that the secondary tile is roamed to the cloud and replicated on other devices where the same user installs the same app).

logo A URI for the square tile image. This can use either the ms-appx:/// or ms-appdata:///local schema. Be sure to avoid storing a dynamically generated image in temporary storage, and avoid deleting it unless all secondary tiles that reference it are deleted.

wideLogo A URI for the wide tile image, again with either the ms-appx:/// or ms-appdata:///local schema.

You can, of course, modify any of these properties after creating the SecondaryTile object along with the remaining properties that let you override the defaults defined in the app manifest: backgroundColor (a Windows.UI.Color value), foregroundText (a ForegroundText value, either dark or light), and smallLogo (a URI again with ms-appx:/// or ms-appdata:///local). Two other properties, lockScreenBadgeLogo and lockScreenDisplayBadgeAndTileText, relate to secondary tiles on the lock screen. We’ll come back to these later in “Background Tasks and Lock Screen Apps,” specifically the subsection “Lock Screen Dependent Tasks and Triggers.”

At runtime, you can also retrieve any of these properties to check the state of the secondary tile if needed. If you modify any properties for a SecondaryTile that has already been pinned, be sure to call its udpateAsync method to propagate those changes.

The requestCreate* methods also have a couple of variations that allow you to control the place-ment of the user consent flyout (again see Figure 13-5). Calling requestCreateAsync by itself results in a default placement in a lower corner of the display. It’s usually better, however, for that flyout to appear close to the command that invoked it. For this purpose requestCreateAsync accepts an optional Windows.Foundation.Point, specifying where to place the lower right corner of the flyout.

With requestCreateForSelectionAsync there are also two variations. The first takes a Windows.Foundation.Rect describing the selection. The flyout will appear above that rectangle if possible. If you expect that this default placement will obscure the secondary tile’s content, you can also pass an optional value from Windows.Popup.Placement to indicate where the flyout should appear relative to that rectangle: above, below, left, and right.

You can play around with all of these options in the Secondary tiles sample. Scenarios 1 and 2 pin and unpin a secondary tile using on-canvas buttons, respectively, with Scenario 7 doing the same through the app bar. We’ll see some of the other scenarios in the sections that follow. For the moment, the pinning function in Scenario 1 (js/pintile.js) shows the creation process using requestCreateForSelectionAsync:

function pinSecondaryTile() {
   var Scenario1TileId = "SecondaryTile.Logo";
   var uriLogo = new Windows.Foundation.Uri(
      "ms-appx:///images/SecondaryTileDefault-sdk.png");
   var uriSmallLogo = new Windows.Foundation.Uri(
      "ms-appx:///images/smallLogoSecondaryTile-sdk.png");

   // Create activation arguments...
   var currentTime = new Date();
   var newTileActivationArguments = Scenario1TileId + " WasPinnedAt=" + currentTime;

   var tile = new Windows.UI.StartScreen.SecondaryTile(Scenario1TileId,
      "Title text shown on the tile",
      "Name of the tile the user sees when searching for the tile",
      newTileActivationArguments,
      Windows.UI.StartScreen.TileOptions.showNameOnLogo, uriLogo);

   // Setting other options
   tile.foregroundText = Windows.UI.StartScreen.ForegroundText.dark;
   tile.smallLogo = uriSmallLogo;

   var selectionRect = document.getElementById("pinButton").getBoundingClientRect();

   tile.requestCreateForSelectionAsync(
      { x: selectionRect.left, y: selectionRect.top, width: selectionRect.width,
        height: selectionRect.height },
      Windows.UI.Popups.Placement.below)
   .done(function (isCreated) {
      if (isCreated) {
         // The tile was successfully created
      } else {
         // The tile was not created
      }
   });
 }

Note As mentioned in Chapter 7, the system flyout displayed when creating a secondary tile (and when removing it, see “Managing Secondary Tiles” below), will cause the app to lose focus and will dismiss a nonsticky app bar as a result. For this reason, Scenario 7 of the Secondary tiles sample keeps the app bar visible by setting its sticky property to true before calling the secondary tile API.

App Activation From a Secondary Tile

Secondary tiles provide a way to activate an app to something other than its default state, similar to how command-line arguments work with desktop or console apps. This process depends entirely on the contents of the secondary tile’s arguments property. When a secondary tile is tapped or clicked, the app’s activated event is fired with an activation kind of launch and the tile’s arguments value in eventArgs.detail.arguments. The app then takes whatever action is appropriate for that data, such as navigating to a particular page of content, retrieving a piece of content from an online source, and so on. In the Secondary tiles sample, the activation code in js/default.js navigates to its Scenario 5 page, where we pass arguments as the options parameter of WinJS.Navigation.navigate:

function activated(eventObject) {
    if (eventObject.detail.kind ===
        Windows.ApplicationModel.Activation.ActivationKind.launch) {
            if (eventObject.detail.arguments !== "") {
                // Activation arguments are present (declared when the
                // secondary tile was pinned)
                eventObject.setPromise(WinJS.UI.processAll().done(function () {
                    // Navigate to Scenario 5, where the user will be shown
                    // the activation arguments
                    return WinJS.Navigation.navigate(scenarios[4].url,
                     eventObject.detail.arguments);
                }));
        } else {
            // Activate in default state
        }
    }
}

The page control (js/LaunchedFromSecondaryTile.js) receives the arguments string in the options parameter of both the processed and ready methods. In the case of the sample it just copies that string to the display:

var page = WinJS.UI.Pages.define("/html/LaunchedFromSecondaryTile.html", {
    processed: function (element, options) {
        if (options) {
            document.getElementById("launchedFromSecondaryTileOutput").innerHTML += "<p>" +
                "App was activated from a secondary tile with the following activation"+
                "arguments : " + options + "</p>";
        }
    },

    ready: function (element, options) {
    }
});

Your own app, of course, will do something much more interesting with arguments!

Managing Secondary Tiles

In addition to the methods and properties to create secondary tiles, the SecondaryTile class has two static methods to generally manage your app’s secondary tiles:

exists Returns a Boolean indicating whether a secondary tile, identified with its tileId, is present on the Start screen. This tells you whether calling a requestCreate* method for a tile with that same tileId will replace an existing one. This is demonstrated in Scenario 4 of the Secondary tiles sample.

findAllAsync Retrieves a vector of SecondaryTile objects that have been created by the app. This will include any tiles roamed from another device (those created with the copyOnDeployment option).65 This is demonstrated in Scenario 3 of the sample.

In addition, there are a few other methods to work with a specific SecondaryTile instance:

requestDeleteAsync and requestDeleteForSelectionAsync Direct analogs, with the same placement variations, to the requestCreate* methods, as deletion of a secondary tile (unpinning) is also subject to user consent. This is demonstrated again in Scenario 2 and 7 of the sample.

updateAsync Propagates any changes made to the SecondaryTile properties since it was added to the Start screen. This is demonstrated in Scenario 8 of the sample.

If you’ve been keep score throughout this section, you might have noticed that I’ve yet to mention Scenario 6 of the sample. That’s because it shows how to make a secondary tile into a live tile with updates. To understand that, we need to look at updates more generally because the mechanisms involved apply to all tiles alike. This just so happens to be the next topic in this chapter—yes, I planned it that way!

Basic Tile Updates

A local update for a tile, as described earlier in this chapter, is one that an app issues while it’s running. Clearly, this is one of the best times to issue updates because it’s highly likely that the app already has the information it needs for those updates to any of its tiles. In a number of cases—especially when an app is not related to a web service—the information needed for the app’s live tiles is available only while it’s running. A game, for example, can send updates showing best scores, new challenges, progress toward achievements, and other kinds of compelling invitations to re-engage with the app. (I must personally admit that this works quite well with the Fruit Ninja game.)

The process of sending a local tile update is very straightforward using the APIs in the Windows.UI.Notifications namespace:

• Create the XML payload, as it’s called, that describes the update within an XmlDocument object. The XML must always match one of the predefined tile templates. You can start with a system-provided XmlDocument, create it from scratch, or use the Notifications Extensions Library that provides an object model and IntelliSense for this.

• Create a TileNotification object with that XML. The XML becomes the TileNotification object’s content property and can be set separately.

• Optionally set the expirationTime and tag properties of the TileNotification. By default, a locally issued update does not expire and is removed only if it’s evicted by a newer update or explicitly cleared. Setting expirationDate will automatically remove it at that particular time. (Cloud-issued notifications automatically expire after three days.) The tag property is a string of 16 or fewer characters that is used to manage the stack of updates that are cycled on the tile. More on this a little later.

• Call TileUpdateManager.createTileUpdaterForApplication to obtain a TileUpdater object that’s linked to your app tile; call TileUpdateManager.createTileUpdater-ForSecondaryTile (chew on that name!) to obtain a TileUpdater object for a secondary tile with a given tileId.

• Call TileUpdater.update with your TileNotification object. (The animation used to bring the update into view is similar to WinJS.UI.Animation.createPeekAnimation, as described in Chapter 11.)

Tip If you issue tile updates or other notifications when your app is running, think about whether it’s also appropriate to issue updates within a resuming event handler if you aren’t going to use other means like periodic updates or push notifications to refresh the tile. It may have been a while since you were suspended, so being resumed is a good opportunity to send updates.

Let’s turn now to the App tiles and badges sample for how updates appear in code. Because the Visual Studio simulator doesn’t enable live tiles and toast notifications, remember to run the sample with the Local Machine or Remote Machine options.

Assuming that we have our update XMLDocument in a variable named tileXml, sending the update just takes two lines of code (see js/sendTextTile.js):

var tileNotification = new Windows.UI.Notifications.TileNotification(tileXml);
Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForApplication()
    .update(tileNotification);

and similarly for secondary tiles in Scenario 6 of the Secondary tiles sample (js/SecondaryTileNotification.js):

var tileNotification = new Windows.UI.Notifications.TileNotification(tileXml);
Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForSecondaryTile(
    "SecondaryTile.LiveTile").update(tileNotification);

The more interesting question is how we create that tileXml payload in the first place. This involves choosing one of the predefined visual tile templates and then choosing a method to create the XMLDocument. Then we’ll see how to use images with the updates along with considerations for branding. Localization and accessibility are additional concerns for tile updates, but we’ll return to that subject later in Chapter 17, “Apps for Everyone.”

Choosing a Tile Template

The first step in creating a tile update is to select an appropriate template from the Tile template catalog. Here you will find descriptions, images, and the exact XML for the 10 available square templates and the 36 available wide templates—yes, 46 different templates in all (so I hope you understand why I’m not showing them all here!). Some are text only, some are image only, some are text and image (wide tiles only), and then there are a number referred to as peek templates. These, if you look at them in the topic linked to above,66 are really composed of two sections that are each the size of the whole tile, as shown below for square tiles (left) and wide tiles (right):

Images

With peek templates you effectively get to show twice the content as the other templates. When a peek update is shown on a live tile, the upper portion will appear first and then the tile will flip or give you a “peek” at the lower portion, and then it will switch back to the upper portion, after which the live tile will switch to the next update in the cycle, if one exists. (The Travel app uses peek templates if you want an example; and the animation that’s employed here is again similar to WinJS.UI.Animation.-createPeekAnimation.) Of course, both sections should contain related content because they are part of the same singular update.

There are several important notes with the template layouts. First, in many of the templates at present, the last line of text will not display if you’re also showing a logo or a short name on the tile (to avoid overlaps). This will likely be changed in the future, but it’s the reality for Windows 8.

Second, images are limited to 1024x1024 and 200KB maximum; if any image exceeds these limits, the entire update will not appear at all. Clearly, it’s better to avoid large images if you can help it because such images just increase memory consumption and possibly network usage (if the image is being downloaded). It’s also good to take the 80%, 100%, 140%, and 180% scale factors into account for tile images. However, if you don’t want to deal with individual scaling factors, size your tile images for 180% and let the system scale them down (which uses a high-quality algorithm so that images will look as good as if you scaled them down with photo-editing software). Also, for photograph, consider using JPEG instead of PNG as the former has better compression for such images.

Third, if you supply an image that doesn’t match the final aspect ratio, the image will be scaled for width and cropped on the top and bottom. Note too that a wide tile is not exactly a 2:1 aspect ratio; at 100% the wide tile is 310x150 pixels, meaning that an image occupying half of it will be 155x150 pixels (not quite square) and those in a collection view (the upper right portion of the rightmost image above) will be 77.5x75.

Fourth, if you want a tile with images and text that doesn’t fit any of the templates, you can always use an image-only template (TileSquareImage and TileWideImage) with a graphic you generate at run time. However, don’t make the tile appear to have separate buttons or other clickable areas: the whole tile always acts as a single unit to invoke the app, so such a design would be misleading.

Hint If you see any apps using tile updates that don’t seem to match any of the templates, they are likely just using the TileWideImage template and drawing all the text and graphics directly.

Scenario 5 of the App tiles and badges sample also provides a very helpful design and experimen-tation tool for tiles, as shown in Figure 13-15. This part of the sample is intended as a tool rather than being code you duplicate in an app. It’s meant to let you easily play around with all the templates and their contents, including images referenced from local and remote sources, without having to write specific code every time. It also lets you exercise the various options for branding the app and sending the result as an update to the sample’s tile on the Start screen.

Images

FIGURE 13-15 Scenario 5 of the App tiles and badges sample is a tool for testing out all the different tile templates.

Creating the Payload, Method 1: Populating Template Content

The first way to create the XML payload for a given template is to use the TileUpdateManager.-getTemplateContent method, to which you pass the name of a template (a value from TileTemplateType). This is shown in Scenario 1 of the sample (js/sendTextTile.js):

function sendTileTextNotificationWithXmlManipulation() {
    var tileXml = Windows.UI.Notifications.TileUpdateManager.getTemplateContent(
        Windows.UI.Notifications.TileTemplateType.tileWideText03);

This method returns an XmlDocument object that contains the structure of the XML for the template but not any specific content. If you run the sample and examine tileXml just after the call above, it will contain only the following—elements but no real data values:

<tile>
  <visual>
    <binding template="TileWideText03">
      <text id="1"></text>
    </binding>
  </visual>
</tile>

The next step, then, is to fill in the blanks (primarily attributes) by using the XmlDocument methods you probably already know (and may or may not love):

   var tileAttributes = tileXml.getElementsByTagName("text");
   tileAttributes[0].appendChild(tileXml.createTextNode(
       "Hello World! My very own tile notification"));

In general, if your tile supports a wide format, include XML for both square and wide formats in the payload, because the user can change the size of the tile at any time. The sample does it this way:

   var squareTileXml = Windows.UI.Notifications.TileUpdateManager.getTemplateContent(
       Windows.UI.Notifications.TileTemplateType.tileSquareText04);
   var squareTileTextAttributes = squareTileXml.getElementsByTagName("text");
   squareTileTextAttributes[0].appendChild(squareTileXml.createTextNode(
      "Hello World! My very own tile notification"));

   var node = tileXml.importNode(squareTileXml.getElementsByTagName("binding").item(0), true);
   tileXml.getElementsByTagName("visual").item(0).appendChild(node);

We’re then ready to send the update to the tile:

   // send the notification to the app's application tile
   Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForApplication()
   .update(tileNotification);
   }

Note that the visual element in the XML supports a version attribute whose default value is 1. This will help accommodate future changes where elements added in newer versions of the XML that arrive on a Windows 8 machine will simply be ignored. The exact tile schema, should be you interested, can be found on the Tile schema reference page.

Creating the Payload, Method 2: XML Strings

Instead of calling TileUpdateManager.getTemplateContent to obtain an XmlDocument with the tile template contents, you can just create that XmlDocument directly from a string. This is just like creating elements in the DOM by using innerHTML instead of the DOM API—it takes fewer overall function calls to create the payload you need and lends itself well to predefining a bunch of mostly populated tile updates ahead of time.

This method is simple: define an XML string with the update contents, create a new XmlDocument, and use its loadXml method to turn the string into the payload. In Scenario 1 we see how this is done to create the exact same payload as in the previous section:

function sendTileTextNotificationWithStringManipulation() {
    // create a string with the tile template xml
    var tileXmlString = "<tile>"
                      + "<visual>"
                      + "<binding template='TileWideText03'>"
                      + "<text id='1'>Hello World! My very own tile notification</text>"
                      + "</binding>"
                      + "<binding template='TileSquareText04'>"
                      + "<text id='1'>Hello World! My very own tile notification</text>"
                      + "</binding>"
                      + "</visual>"
                      + "</tile>";

    var tileDOM = new Windows.Data.Xml.Dom.XmlDocument();
    tileDOM.loadXml(tileXmlString); // Good idea to put this in a try/catch block

    var tile = new Windows.UI.Notifications.TileNotification(tileDOM);
    Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForApplication()
        .update(tile);
}

Clearly, this method is very simple but has the drawback of requiring you to do manual escaping. It is also more difficult to debug. (Looking for tiny errors in strings in not my favorite pastime!) Fortunately, there is a third available method: the Notifications Extensions Library, which offers the simplicity of using strings with a high degree of reliability.

Creating the Payload, Method 3: The Notifications Extensions Library

The third means of creating the necessary XmlDocument for a tile update is to use what’s called the Notifications Extensions Library. (Yes, it’s a double plural.) This is a WinRT component written in C# that’s included with a number of the SDK samples, including the App tiles and badges sample we’re looking at here. (Notice that it’s included in the project’s References.) We’ll be looking at the structure of such components in Chapter 16, “WinRT Components.” It’s likely that this library will become part of the Windows API in the future, so we do encourage developers to leverage it.

The library makes it easier to populate a template through object properties rather than XmlDocument methods, and because it’s been very well-tested within Microsoft it’s a more robust approach than creating an XmlDocument directly from strings. Here’s how it’s used in Scenario 1 to create, once again, the same payload we’ve already seen:

function sendTileTextNotification() {
    var tileContent =
        NotificationsExtensions.TileContent.TileContentFactory.createTileWideText03();
    tileContent.textHeadingWrap.text = "Hello World! My very own tile notification";

    var squareTileContent = NotificationsExtensions.TileContent.TileContentFactory
        .createTileSquareText04();
    squareTileContent.textBodyWrap.text = "Hello World! My very own tile notification";
    tileContent.squareContent = squareTileContent;

    Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForApplication()
        .update(tileContent.createNotification());
}

Simply said, the library’s TileContentFactory object provides methods to create objects equivalent to the XML documents provided by TileUpdateManager.getTemplateContent. As shown in the code above, those objects have properties equivalent to each field in the template, and when you’re ready to pass it to TileUpdater.update, you just call its createNotification method.

The other reason this library exists is to simplify the process of creating an ASP.NET web service for periodic updates and push notifications (where the latter can send tile updates, badge updates, and toast notifications). Instead of creating the XML payloads manually—a fragile and highly error-prone practice at best—the service can use the Notifications Extensions Library to easily and consistently create the XML for all these notifications.

Because the object model in the library clearly describes the XML, it’s fairly easy to use. There is also a topic in the documentation for it called Quickstart: Using the NotificationsExtensions library in your code. The samples we look at in this chapter also show most use cases.

Using Local and Web Images

Scenario 1 of the sample, as we’ve seen, shows tile updates using text, but the more interesting ones include graphics as well. These can come either from the app package, local app data, or the web, using ms-appx:///, ms-appdata:///local, and http:// URIs, respectively. These URIs are simply assigned to the src attributes of image elements within the tile templates. (These are image, not img as in HTML.) Note again that the first two URIs typically have three slashes at the beginning to denote “the current app”; http:// URIs also require that the Internet (Client) capability be declared in the app’s manifest.

Scenario 2 of the sample (js/sendLocalImage.js) shows the use of ms-appx:/// for images within the app package, with variants for all three methods we’ve just seen to create the payload. When using XmlDocument methods, setting an image source looks like this:

var tileImageAttributes = tileXml.getElementsByTagName("image");
tileImageAttributes[0].setAttribute("src", "ms-appx:///images/redWide.png");

The Notifications Extensions Library gives us properties to which we can assign a URI:

var tileContent = NotificationsExtensions.TileContent.TileContentFactory
    .createTileWideImageAndText01();
tileContent.textCaptionWrap.text = "This tile notification uses ms-appx images";
tileContent.image.src = "ms-appx:///images/redWide.png";

And when using XML strings, you can just include the URI directly in the image element.

Scenario 3 (js/sendWebImage.js) shows the same things except you can enter an http:// URI of your choice. This is a good way to see the effects of pointing to images that have varying aspect ratios as well as those that exceed the allowable 1024px dimensions and 200KB file size. As you’ll see, the updates simply aren’t shown in those cases.

As for ms-appdata:///local URIs (roaming and temp are not allowed), their use is demonstrated in Scenario 8 where you choose an image with the file picker and the sample copies it to the local app data folder. It then references that file with an ms-appdata:///local URI in the update payload (js/imageprotocols.js):

tileContent = NotificationsExtensions.TileContent.TileContentFactory.createTileWideImage();
tileContent.image.src = "ms-appdata:///local/" + imageRelativePath;

The same scenario lets you play with in-package and remote URIs as well, as does the tile update designer in Scenario 5. I also updated the Here My Am! app for this chapter (in the companion content) with a peek tile update containing the most recent image and the location; see “Sidebar: PNG vs. JPEG Image Sizes” below.

Speaking of tools and images, also check out Scenario 10 in the SDK sample. This gives you another helpful tool for tile updates where you can crop and adjust images according to varying pixel densities so that they’ll work well with a selected tile template. You can save the images you adjust for inclusion in your app package, and the code for the scenario can also be used to adjust images at run time. Like I said, very helpful!

A final capability with images is an option to have Windows automatically append a query string to http:// URIs. This query string will describe the current scaling factor, contrast setting (for accessibility), and language. This enables web services to adjust images accordingly, avoiding the need to handle such concerns in the app itself. As described in the Tile schema reference, specifically for the image element, you indicate this option by setting the addImageQuery attribute of image to true (also supported on the visual and binding elements):

// XmlDocument form
var tileImageAttributes = tileXml.getElementsByTagName("image");
tileImageAttributes[0].setAttribute("addImageQuery", "true");

// XML string form (other lines omitted)
var tileXmlString = /* ... */ "<image id='1' addImageQuery="true"
    src='ms-appx:///images/redWide.png'/>" /* ... */

// If using Notifications Extensions Library (see Scenario 9 in the sample)
var tileContent = NotificationsExtensions.TileContent.TileContentFactory
    .createTileWideImageAndText01();
tileContent.image.src = "ms-appx:///images/redWide.png";
tileContent.image.addImageQuery = true;

In all of these cases, the appended string will be of the form

?ms-scale=<scale>&ms-contrast=<contrast>&ms-lang=<language>

where <scale> is 80, 100, 140, or 180, <contrast> is standard, black, or white, and <language> is a BCP-47 language tag such as en-US, jp-JP, de-DE, and so forth. All of these are described on the Globalization and accessibility for tile and toast notifications in the documentation, including how to localize update text.

When considering tile images for the larger 140% and 180% scales, the encoding you use for your images can make a big difference and keep them below the 200K size limit. As we saw in “Branding Your App 101” in Chapter 3, a wide tile at 180% is 558x270 pixels and a square is 270x270 pixels. With the wide tile, a typical photographic PNG at this size will easily exceed 200K.

I encountered this when adding tile support to Here My Am! in this chapter, where it makes a smaller version of the current photo in the local appdata folder and uses ms-appdata:///-local URIs in the tile XML payload. At first, I borrowed code from Scenario 10 of the App tiles and badges sample, as we’ve been working with here, to create a PNG from the img element using a temporary canvas and the blob APIs. This worked fine for a 270x270 tile image (a 180% scale that can be downsized), but for a 558x270 the file was too large. So I borrowed code from Scenario 3 of the Simple Imaging sample to directly transcode the StorageFile for the current image into a JPEG, where the compression is much better and we don’t need to use the canvas. This code is in the transcodeImageFile function in pages/home/home.js, a routine that we’ll also rewrite in Chapter 17 using C# in a WinRT component.

Such considerations are certainly important for services that handle the addImageQuery parameters for scale. For larger image sizes, it’s probably wise to stick with the JPEG format to avoid going over the 200K limit.

Branding

If you’re the kind of person who likes to read XML schema specs (like the Tile schema reference I pointed to a few moments ago), you might have noticed another attribute of the visual and binding elements called branding. This can be set to none, logo (the default), or name to indicate whether to include the app’s small logo or short name on the tile, both of which are provided in the app’s manifest. Scenario 5 of the App tiles and badges sample lets you play with these variations.

The other bits of the manifest that affect a tile update are the Foreground Text and Background Color settings in the Application UI section. These define how tile text appears for all tile updates (and toasts for that matter), and they cannot be altered in the tile payload. This keeps the branding of the app consistent between updates; users would certainly find it confusing if multiple tiles from the same app showed up in different colors.

As a quick example, the SDK sample we’ve been working with here uses Light foreground text and a background color of #00b2f0. If I go to Scenario 5, choose the TileWideText09 template, add some text, and select Logo for the branding (where the small logo contains a block with “SDK” in it), the result is as follows:

Images

Cycling, Scheduled, and Expiring Updates

Although you might read the heading for this section and think it’s just going to be a grab bag of randomness, all it really means is that we’re looking at additional methods of the TileUpdater object and revisiting the two properties of the TileNotification object that we already mentioned. Simply said, now that we’ve seen how to do all the basic tile updates we’re ready to start exploring the additional capabilities. Again, everything here applies to all tiles in the app.

First is the ability to programmatically clear all updates and reset the tile to its default state as defined in the manifest. This happens with a simple call to TileUpdater.clear (shown in Scenario 1):

Windows.UI.Notifications.TileUpdateManager.createTileUpdaterForApplication().clear();

The next capability, as already mentioned, is to set the TileNotification.expirationTime property before sending that notification to TileUpdater.update. This ensures that a locally issued notification will be automatically removed, and it lets you override the default three-day expiration period for cloud-issued updates. The update will appear immediately (at the next tile refresh, that is) and will then be removed from the tile after it expires. This is demonstrated in Scenario 7 of the sample—sending an update with an expiration date will display an update as on the left below. When it expires, it’s removed, which in this case causes the tile to revert to its default state, as shown on the right (and yeah, I’m working on this book on a Sunday night!):

Images

To delay the appearance of an update until a specified time, with or without an expiration, you do something a little different at the beginning: instead of creating a TileNotification object to send to the updater, create a ScheduledTileNotification and send it to TileUpdater.-addToSchedule.

A ScheduledTileNotification is exactly the same as a TileNotification (including the expiration time) except that it contains an extra property called deliveryTime that indicates when—in UTC time, not local time!—the tile should first appear. For an example of this we have to take a brief detour to Scenario 1 of the Scheduled notifications sample. But all that’s really different is that we take whatever XmlDocument we’ve created with the payload—through any of the methods covered earlier—and create the notification with the delivery time. Here’s a condensation of the code in the sample’s js/scenario1.js file:

// Namespace variable
var Notifications = Windows.UI.Notifications;

// The delay in delivery time from the sample's control
var dueTimeInSeconds = parseInt(document.getElementById("futureTimeBox").value);

// The actual delivery date and time
var currentTime = new Date();
var dueTime = new Date(currentTime.getTime() + dueTimeInSeconds * 1000);

// In here we create the XmlDocument in the variable tileDOM

// Now create the update with the delivery date
var futureTile = new Notifications.ScheduledTileNotification(tileDOM, dueTime);
Notifications.TileUpdateManager.createTileUpdaterForApplication().addToSchedule(futureTile);

Other than these small changes, everything else about the tile update is the same as before.

It’s certainly possible, as you can guess, to queue up many scheduled updates. At any time you can call TileUpdater.getScheduledTileNotifications to obtain a vector of active Scheduled-TileNotification objects. You can also remove any of those updates with TileUpdater.-removeFromSchedule.

What happens if you schedule a series of updates that will end up being active at the same time? In the Scheduled notifications sample, for instance, issue a series of tile updates for 10 seconds from now, and then quickly switch to the Start screen to see the results. Those updates will appear in sequence, and one of them might actually be dropped if another update is scheduled right on its heels. And once you reach the last update, it just stays there until it expires, the tile is cleared, or some new update comes along.

In such cases it would be better to have the tile cycle through a series of tiles, thereby keeping the tile active with the more than just the last update.

Live tiles support cycling through up to five updates, where the duration of each is controlled by the system so that the whole Start screen has a consistent look and feel. To enable this you must first call TileUpdater.enableNotificationQueue(true), and you can call it with false to disable cycling. The queue itself is first in, first out (FIFO; you cannot control the order otherwise), so the oldest notification is removed if a new one is added when the queue is already at maximum. In other words, if you enable the queue and issue updates as we’ve been doing, the five most recent updates will cycle.

You might want to selectively replace existing updates already in the queue rather than rely on the FIFO behavior (or calling TileUpdater.clear and reissuing the update you want to retain). This is the purpose of the tag property in TileNotification and ScheduledTileNotification. The tag is again just a maximum 16-character string that simply identifies a particular update. If the queue is enabled, a new update with any given tag will replace any update already in the queue with the same tag. If that tag doesn’t exist, the update will replace the oldest in the queue. So, for example, a news app might have five tags for different categories of headlines such as world, local, politics, business, and health; a stock app would obviously use tags for different ticker symbols. Similarly, a weather app might tag updates with a zip code or other location identifier.

You can play with all this in Scenario 6 of the App tile and badges sample. In the process you might note that when activating an app from a cycling live tile, it does not receive an indication as to which update is currently shown. For this reason, it’s currently recommended that activating a cycling live tile opens the app on a hub page that displays relevant content for all the updates together.

Badge Updates

The last bit you can use to update a live tile is a badge. I’ve kept this topic separate because it works through a separate API and is not part of the tile update XML payloads we’ve been using.

To review, badges are simply small glyphs—a one- or two-digit number, or one of a small number of symbols—that appear on a tile regardless of any other update activity. They are meant to indicate the status of the app rather than a piece of content, so like a logo or name they are not animated with other updates. However, badge changes are separately animated using WinJS.UI.Animations.updateBadge, as briefly noted in Chapter 11.

How you send badges to your tile is structurally similar to a tile update. Start by creating an XmlDocument payload for the badge update by using a template from the Badge image catalog or using the Notifications Extensions Library, which contains full support for badges. In the case of badges, it’s really overkill to speak of an XML “document” because it contains only one element, badge, with one attribute, value, for which you can indicate a number from 1–99 (anything over that will display 99+) or one of 11 specific glyphs, as shown below. Note that although the glyphs are shown here against a blue background, the actual color will be the Background Color in your manifest:

Images

If you like, you can use the BadgeUpdateManager.getTemplateContent function to obtain an XmlDocument with such contents; there’s a bit of sample code on this method’s reference page that shows how. But because the XML is so simple, it’s just as easy to create the object from a string by using new Windows.Data.Xml.Dom.XmlDocument followed by a call to its loadXml method, as we’ve seen with tiles. The Notifications Extensions Library also has methods for this and doing updates. Both of these approaches are demonstrated in Scenario 6 of the App tiles and badges sample.

However you create it, the next step is to instantiate a BadgeNotification with that XmlDocument:

var badge = new Windows.UI.Notifications.BadgeNotification(badgeDOM);

This notification object also supports an expirationTime property just like tiles do. That aside, the last step is to call BadgeUpdateManager.createBadgeUpdaterForApplication to obtain a BadgeUpdater for your app tile or—you can predict this one—BadgeUpdateManager.create-BadgeUpdaterForSecondaryTile to obtain a BadgeUpdater for a secondary tile with a given tileId. After you obtain your BadgeNotification (and again, the Notifications Extensions Library can help here), you then call BadgeUpdate.update:

Windows.UI.Notifications.BadgeUpdateManager.createBadgeUpdaterForApplication()
   .update(badge);

or:

Windows.UI.Notifications.BadgeUpdateManager.createBadgeUpdaterForSecondaryTile(
    "SecondaryTile.LiveTile").update(badge);

And as with tiles, BadgeUpdater.clear removes the badge entirely, which is equivalent to sending an update with the value of none. That’s it.

Beyond that, the BadgeUpdater class has just two additional methods, startPeriodicUpdate and stopPeriodicUpdate, which are also found on the TileUpdater class. And wouldn’t you know it? Periodic updates just so happen to be our next topic—yes, I planned it this way too!

Included with the many improvements to Task Manager for Windows 8 is the ability to track your app’s network traffic for tile updates. Run Task Manager, make sure you click More Details in the lower left, and then click the App History tab. Network traffic for tile updates is shown on the rightmost column. This number will typically be small, but it’s a metric you can monitor to see whether updates become excessive.

Images

Periodic Updates

As described earlier in this chapter, periodic updates configure the system to automatically request updates from a web service on behalf of an app. Provided that the app has declared the Internet (Client) capability, this enables the app to continually keep its live tiles fresh without needing to run at all.

Periodic updates are great proof that Microsoft really does listen to developer feedback. When the first Developer Preview of Windows 8 was released in September 2011, many developers were very interested in implementing live tiles but it could only be done with push notifications and the Windows Push Notification Service, even if the tiles only needed low-frequency updates. In other words, push notifications were total overkill for apps that needed to get only a bit of data from a web service every once in a while to create their updates. So developers asked, “Is it possible to have my app just run in the background, periodically request data from my service, and then issue tile or badge updates?”

It was a completely legitimate request, but as described earlier, background tasks are very carefully controlled and allowed only for very specific scenarios. Hearing this feedback, the tiles and notifications team at Microsoft studied the problem and found that creating a new class of background task would also be overkill for low-frequency tile updates. Furthermore, they found that even if apps could use a background task for this purpose, they’d all pretty much do the same thing: poll data from a service and populate a tile or badge template. So instead of adding a background task, they added a new API for system-managed periodic updates.

This API consists of the following methods of the TileUpdater and BadgeUpdater classes:

TileUpdater.startPeriodicUpdate and BadgeUpdater.startPeriodicUpdate Configure Windows to request an update from a given URI with a specified period (see below). These calls remove any previous URIs registered for the tile. An app can specify an optional date and time around which regular polling should begin, and in all cases the first request will happen immediately (very helpful for debugging!). A good time to call these is when the app is launched, when it’s resumed, and when a configuration changes that might alter the URI.

TileUpdater.stopPeriodicUpdate and BadgeUpdater.stopPeriodicUpdate Cancels the current periodic update process but does not clear the tile of existing updates.

TileUpdater.startPeriodicUpdateBatch For tile updates only, is identical to startPeriodicUpdate but accepts an array of up to five URIs, automatically creating an update queue with the results (replacing any previous URIs). Note that TileUpdater.enableNotificationQueue must be set to true prior to using this method, as described earlier in the “Cycling, Scheduled, and Expiring Updates” section.

In all these cases, each URI is represented by a Windows.Foundation.Uri object and the polling period is set with a value from the PeriodicUpdateRecurrence enumeration. Values are halfHour, hour, sixHours, twelveHours, and daily giving a clear indication that periodic updates are meant for content that changes relatively infrequently, like the weather, daily offers from local retailers (in which case you’d use start time), or the phases of the moon. For anything that requires more timely delivery, like appointment reminders, traffic conditions, current sports scores, or online auction status, you’ll need to use push notifications.

In addition, all these updates can employ tags and expiration times as with local updates. One detail is that at any given polling interval, a web service can return only a single update payload—hence the need for startPeriodicUpdateBatch. That said, if the notification queue is enabled and the updates from a single web service contain different tags, the live tile will behave the same as if those updates were issued locally: the most recent update for each tag (up to five) will be cycled through in the queue.

Hint The periodic update API does not directly provide a means to authenticate with the service. This typically isn’t necessary because periodic updates are not designed to be user-specific. However, you can certainly include encrypted credentials in the URI with a query string. You might also be able to use the Enterprise Authentication capability if the app is running on a domain-joined system.

The app side of the periodic update scene is demonstrated in the Push and periodic notifications client-side sample. Specifically, see scenarios 4 and 5, which are somewhat general tools to employ the TileUpdater and BadgeUpdater methods with a given service URI just as I’ve just described. A few lines of that code (condensed from js/scenario4.js) appear as follows:

var notifications = Windows.UI.Notifications;
var updater = notifications.TileUpdateManager.createTileUpdaterForApplication();

updater.enableNotificationQueue(true);
updater.startPeriodicUpdate(urisToPoll[0], recurrence);
updater.startPeriodicUpdateBatch(urisToPoll, recurrence);

The real work of periodic updates, however, lies in the service itself, whose responsibility it is to return the appropriate XML from which Windows can create an update. Being able to even run the client-side sample requires some service to which we can make requests, and unfortunately the Windows SDK does not provide one. So let’s remedy that situation with a service of our own.

Because you’ll likely use the client-side sample to play around with your own update service, though, there are two changes you should make, specifically to clear existing updates in the functions that stop polling. In js/scenario4.js, change the stopTilePolling function to read as follows:

function stopTilePolling() {
   var updater = notifications.TileUpdateManager.createTileUpdaterForApplication();
   updater.clear();
   updater.stopPeriodicUpdate();
   WinJS.log && WinJS.log("Stopped polling.", "sample", "status");
}

Similarly, change stopBadgePolling in js/scenario5.js to read as follows:

function stopBadgePolling() {
   var updater = notifications.BadgeUpdateManager.createBadgeUpdaterForApplication();
   updater.clear();
   updater.stopPeriodicUpdate();
   WinJS.log && WinJS.log("Stopped polling.", "sample", "status");
}

Without these changes, old updates will persist on the tile even after you stop the updates. If you then change your web service but it has an error in the XML, you won’t see any change on the tile and might think that the update worked when it really didn’t. Trust me: making these small changes will simplify your life!

Web Services for Updates

Creating a web service for periodic updates means creating a web page at some given URI whose sole purpose is to respond to an XmlHttpRequest with XML content for a TileNotification or BadgeNotification object. Ideally, such a page also handles the scaling, accessibility, and localization parameters provided in the query string described earlier in “Using Local and Web Images.”

The page can be implemented using whatever language and tools you want, such as PHP or ASP.NET. In fact, unless you really enjoy programming in Notepad, you’ll certainly want to utilize a good web development tool! Visual Studio Express for Windows 8 is not actually equipped for this task; the full version of Visual Studio 2012 is. You might also look into Visual Studio Express 2012 for Web as another option; more on this in a moment. If you use ASP.NET, remember again that you can again employ the Notifications Extensions Library for easily creating the tile XML.

Some examples of pages that provide tile updates are given in the Creating a great tile experience (Part 2) post on the Windows Developers Blog. Based on those examples, here is a trivial (but functional) one-liner PHP page that will post XML for a badge update with the current day of the month:

<?phpecho "<badge value='".date("j")."'/>"; ?>

For proper XML we should also include a header element, which also works:

<?php echo '<?xml version="1.0" encoding="utf-8"?>';
     echo "<badge value='".date("j")."'/>"; ?>

Drop this code into a .php file (see HelloTiles/dayofmonthservice.php in the companion content for this chapter) on whatever web server you might have access to and voila! There’s a very basic service that delivers badge updates. You can use this in Scenario 5 of the Push and periodic notifications client-side sample—enter your page’s URI in the box, press the button to start polling, and then check the sample’s tile on the Start screen tile. In a few seconds you should see the day of the month appear as a badge. (Of course, with this ultrasimplistic example the date will reflect the local time on the web server rather than the device, which could be completely mismatched. A real service would be sensitive to time zone and other locale-specific considerations.)

Images

Tip The tile and badge updaters are very sensitive to properly formed XML. In the PHP code above, leaving off the closing / for the badge element will make the update fail to appear. Avoiding such trivial errors is again why the Notifications Extensions Library was created, at least for ASP.NET. I’m hoping that some enterprising reader might consider a similar project for PHP and other server-side languages!

Going back to the Windows Developer Blog post mentioned earlier, I want to point out that the ASP.NET example given there—the one that begins with @{—is using the ASP.NET Razor syntax (typically in a .cshtml file), introduced with Microsoft WebMatrix. Razor/WebMatrix, along with tools such as Visual Studio Express 2012 for Web and a whole lot else, can be installed through the Web platform installer. To familiarize yourself with Razor, which works much in the same way as PHP, start with Walkthrough: Creating a Web Site using Razor Syntax in Visual Studio.

To make that long story short, here are the steps in Visual Studio Express 2012 for Web to create a simple tile update service based on the Razor code in the blog post:

• Select File > New Web Site from the menu.

• In the New Web Site dialog, select ASP.NET Web Site (Razor v1), give it a project name and folder, and press OK. Call this site HelloTiles.

• Once the project is created, you should see the Default.cshtml file opened.

• Copy and paste the following Razor code into that file, replacing the default contents. The little piece of C# code at the top for the weekDay variable is something we’ll use in the next section to demonstrate debugging; it’s not used in generating the XML. Here, note that I tested and generated the XML contents by using the tile designer in Scenario 5 of the App tiles and badges sample (see Figure 13-15); this saved me lots of time wondering whether my XML was correct.

    @{
      //
      // This is where any other code would be placed to acquire the dynamic content
      // needed for the tile update. In this case we'll just return static XML to show
      // the structure of the service itself.
      //
      var weekDay = DateTime.Now.DayOfWeek;
    }
    <?xml version="1.0" encoding="utf-8" ?>
    <tile>
        <visual lang="en-US">
            <binding template="TileSquarePeekImageAndText02" branding="none">
                <image id="1" src="http://www.kraigbrockschmidt.com/images/Liam07.png"/>
                <text id="1">Liam--</text>
                <text id="2">Giddy on the day he learned to sit up!</text>
            </binding>
            <binding template="TileWideSmallImageAndText04" branding="none">
                <image id="1" src="http://www.kraigbrockschmidt.com/images/Liam08.png"/>
                <text id="1">This is Liam</text>
                <text id="2">Exploring the great outdoors!</text>
            </binding>
        </visual>
    </tile>

• Run the website in Internet Explorer using the Debug > Start Debugging command or the Internet Explorer toolbar button (where you’d find the Local Machine or Simulator options in Visual Studio Express 2012 for Windows 8). This will launch Internet Explorer with a URI like http://localhost:52568/HelloTiles/Default.cshtml where the port number is what routes the URI to the site running in the debugger. If you need to set up your localhost server, see the next section, “Using the Localhost.”

• Run the Push notifications app sample, switch to Scenario 4, paste the URI into the URI1 field, and press the Start periodic updates.

• If all is well, you should see the wide tile update as follows. (OK, so it’s another shameless picture of my kid…what can I say? You have to give us fathers a break!)

Images

• If you use the Start screen’s app bar command to make the tile smaller, thereby using the square tile payload in the XML, you should see it switch between to another gratuitous picture of my kid and peek text:

Images

The complete website code for all this can be found in the HelloTiles example in this chapter’s companion content. As simple as it is, it provides the basic framework in which you can add code to generate more dynamic results. In the top part of the file, within the @{ }, you can write whatever code you need by using C#.

Generally speaking, a real service that provides tile and badge updates would probably be connected on the server side to some other useful source of information, perhaps to an always-running process that can monitor other sites, extract the desired data, and generate updates. Those updates can be returned from page requests, as we’ve seen here, or fed directly to WNS so that they can be pushed directly to specific clients. We’ll come back to this subject in “Push Notifications and the Windows Push Notification Service” later in this chapter.

For now, a more pressing question is this: how does one actually debug such a service? Fortunately, the Visual Studio tools make this very straightforward through the localhost.

Using the Localhost

Debugging a tile and badge update service with periodic notifications can be a difficult proposition. You can just enter your service’s URI in a browser and use its View Source command to examine the XML, but how do you step through that server-side code to isolate problems?

The solution is to run your service on your local machine, as we just did in the previous section, where the URI references your localhost server, however you want to set it up. You can install a server like Apache, of course, or you can use the solution that’s built into Windows and integrated with the Visual Studio tools: Internet Information Services (IIS).

To turn on IIS in Windows, go to Control Panel > Turn Windows Features On Or Off. Check the Internet Information Services box at the top level, as shown below, to install the core features:

Images

Once IIS is installed, the local site addressed by http://localhost/ is found in the folder c:\inetpub\wwwroot. That’s where you drop something like the PHP page described in the last section so that you can use a URI like http://localhost/dayofmonthservice.php in the Push notifications sample (Scenario 5, in this case, for badge updates).

With the web page running on the local machine, you can hook it into whatever tools you have available for server-side debugging. Here it’s good to know that access to localhost URIs—also known as local loopback—is normally blocked for Windows Store apps unless you’re on a machine with a developer license, which you are if you’re been running Visual Studio or Blend. This won’t be true for your customer’s machines, though! In fact, the Windows Store will reject apps that attempt to do so.67

To use PHP with IIS, you might need to install it through Microsoft’s Web platform installer or the server-side code won’t execute properly. After PHP installation, try entering the URI for the PHP page in your browser. If you get an error message that says “Handler PHP53_via_FastCGI has a bad module” (yeah, that’s really helpful!), return to the Turn Windows Features On Or Off dialog shown earlier, navigate to Internet Information Services > World Wide Web Services > Application Development Features, check the box for CGI, and press OK. Once the CGI engine is installed, your PHP page should work.

If you plan to work in ASP.NET or Razor, I highly recommend you also install Visual Studio Express 2012 for Web through Web platform installer. When you run a website in its debugger, it assigns a port on localhost such as http://localhost:53528 and launches Internet Explorer with that URI. The port links the browser to the debugger, so if you set a breakpoint in the page code, the debugger will stop at that point whenever there’s a page request, allowing you to step through the code with the same features we’ve been enjoying in writing Windows Store apps.

For example, load up the HelloTiles example site with this chapter in Visual Studio Express 2012 for Web, set a breakpoint on the var weekDay line at the top, and start debugging. Once Internet Explorer has loaded default.cshtml, copy and paste its URI into Scenario 4 of the Push notifications sample. Press the Stop Periodic Updates button followed by the Start Periodic Update button to force a new request to the URI and—magic!—you should hit the breakpoint in the service:

Images

Windows Azure

When you’re ready to upload an app to the Windows Store and have real customers using your web service, you’ll need to consider where, exactly, you’ll host that service so that it can scale to what hopefully becomes a very large customer base! During your development and testing process, of course, you can host the service anywhere you want because only a few instances of your app will ever call upon it. But if your app is acquired by many customers and each instance of that app starts banging on the host server for tile and badge updates, that host might soon become overloaded!

For this reason you should investigate services like Windows Azure, where more server power can be added when it’s necessary and scaled back when it’s not (and you pay only for what is actually used). To get started, visit http://www.windowsazure.com where you can set up a free 90-day trial for a hosted site. The Windows Azure site also provide direct support and SDKs for .NET, node.js, PHP, Java, and Python, along with Visual Studio Express 2012 with Web for Windows Azure SDK—all available again through the Web platform installer. You might also be interested in the Windows Azure Toolkit that provides project templates, samples, and other resources for creating services on Windows Azure.

Tip As of this writing, Windows Azure has support for .NET Framework 4.0 but not .NET Framework 4.5, so be sure to check the target framework in your project’s Build settings before deployment. (Right-click your project in Visual Studio Web, select Property Pages, and click Build—see image below). When I deployed my service targeting version 4.5, pages like Default.cshtml produced errors.

Images

As a brief walkthrough to get you started, I started my Windows Azure trial, installed the Windows Azure SDK for .NET, and deployed the HelloTiles example service with these steps:

• Go to the Windows Azure Management Portal, and sign in with your account.

• Create a new website with some URI. I used ProgrammingWin8-JS-CH13-HelloTiles, making the full site URI http://programmingwin8-js-ch13-hellotiles.azurewebsites.net/. After this step, my portal looks like this:

Images

• To upload the site, you first need to set up FTP credentials. Click the site in the list, which takes you to its specific dashboard. Under Publish Your App, click Set Up Deployment Credentials and enter a username and password.

• Click Dashboard along the top of the window, and scroll down the right side to find the FTP hostname:

Images

• In Visual Studio Express 2012 for Web, right-click the project and select Copy Web Site. In the dialog that appears, click Connect along the top to open the Open Web Site dialog (below). Select FTP site on the left, enter the FTP hostname on the top, enter site/wwwroot in Directory, and then enter your credentials at the bottom. Make sure to prefix your username with the site name and a backslash (for example, ProgrammingWin8-JS-CH13-HelloTiles\JohnQUser) or you’ll be very confused by Azure’s refusal to let you through the door! Finish by clicking Open.

Images

• Once Visual Studio Express 2012 for Web is connected to the Azure site, you can upload your files.

• Once that’s complete, you should be able to use the site URI plus Default.cshtml as the URI for the tile update service. For instance, try http://programmingwin8-js-ch13-hellotiles.azurewebsites.net/dayofmonthservice.php with the Push notifications sample, Scenario 5, and http://ProgrammingWin8-JS-CH13-HelloTiles.azurewebsites.net/Default.cshtml with Scenario 4 and you’ll see the same results as when we used localhost. You can also just visit these URIs directly to see the XML they’re producing.

With this, you now have the ability to scale up your Windows Azure hosting, with your app supplying the hosted URI to the periodic update API. This also puts you in a good position to use push notifications, as we’ll see later, but because those are also often used with toasts, let’s see how toasts work next.

Toast Notifications

So far in this chapter we’ve exhausted the subject of tiles and tile updates, which is actually a great prelude to our next topic, toast notifications. This is because the process of creating and issuing toasts is quite similar to that for tiles and is simplified by the fact that there are no periodic updates for toasts: they either come from the running app, from background tasks, or through push notifications, as we’ll see in “Push Notifications and the Windows Push Notification Service” below. Fortunately, the topic of toasts is considerably shorter than that of tiles. Here are the salient aspects of toasts:

• Toasts always use the app’s Background Color and Foreground Text settings in the manifest for branding, along with the small logo. There are no means to override this; the branding attribute in the XML is ignored for toasts.

• An app must set the Toast Capable setting in its manifest for any toasts to appear on its behalf. This is found in the Application UI > Notifications area:

Images

• As shown long ago in Figure 13-8, the user can disable toasts for a particular app or disable them globally (which I find helpful when recording a screencast!). System administrators can also disable toasts by policy. To check this status programmatically, look at the Toast-Notifier.setting property, a value from the NotificationSetting enumeration that will be enabled, disabledForApplication, disabledForUser, or disabledByGroupPolicy.

• When enabled, toasts always appear in the upper right corner of the screen (left-to-right languages) or the upper left corner (right-to-left languages). This is not configurable.

• Toasts are managed through instances of the Windows.UI.Notifications.ToastNotification or Windows.UI.Notifications.ScheduledToastNotification classes. The first supports an expirationTime property; the scheduled toast supports deliveryTime, snoozeInterval, and maximumSnoozeCount properties.

• As with tiles, the content of toasts are created with an XML payload from one of four text-only and four image-plus-text templates, as shown on the Toast template catalog. Toast templates are acquired from the ToastNotificationManager object’s getTemplateContent method, can be created from strings, or can be created through the Notifications Extensions Library. Various options can be set in the XML:

• Toasts can include text and an image, where the image can come from the app package, app data, or a remote source (given Internet Client capability). Images have the same limits as with tiles: 1024x1024 maximum resolution and 200KB maximum file size. Unlike tiles, however, if the image exceeds the limits, the notification will still show but with a gray placeholder image instead.

• Toasts can specify a predefined sound to play when the toast appears, with a looping option. Custom sounds are not supported.

• By default, toasts appear for seven seconds (five seconds opaque plus a two-second fade) or until activated or dismissed. (The opaque duration is available through the Windows.UI.ViewManagement.UISettings.messageDuration property.) You can issue long-duration toasts, looping toasts, and recurring toasts that appear a given number of times with some interval in between.

• A toast is issued through the ToastNotifier class, namely the show and addToSchedule methods for immediate and scheduled toasts, respectively. The ToastNotifier also provides methods to manage previously scheduled toasts.

• Like secondary tiles, toast notifications can (and generally should) be created with specific arguments in the XML payload that will be passed to the app’s activated event handler with the activation kind of launch. Without such arguments, no activated event is raised, but otherwise an app handles toast notifications exactly as it would a secondary tile. Alternately, an app can listen to specific events that the toast itself will raise when it’s activated or dismissed.

The following sections provide details on a number of these steps, using the Toast notifications sample and Scheduled notifications sample for reference. We also recommend you review the Guidelines and checklist for toast notifications.

Tip As noted before, toasts are not enabled within the Visual Studio simulator; you must run these samples on the Local Machine or a Remote Machine to see the toasts.

Creating Basic Toasts

Let’s start with Scenarios 1, 2 and 3 of the Toast notifications sample, which shows how to issue toasts from a running app using the text and text+image templates. As shown in Figure 13-16 and Figure 13-17 (for text-only and text+image toasts, respectively), up to three toasts can be visible at one time. Remember that you must have Toast Capable set to Yes in the app manifest for any of this to work.

Images

FIGURE 13-16 Issuing text toasts through Scenario 1 of the Toast notifications sample. (The bottom of the app is cropped.)

Images

FIGURE 13-17 Issuing text+image toasts through Scenario 3 of the sample. (The bottom of the app is again cropped.) Scenario 2 does the same thing with in-package images that aren’t nearly as interesting, in my paternal opnion, as my cute kid!

Just as we saw earlier with tiles, the sample shows how to create the XML payloads for toasts by using template content from ToastNotificationManager.getTemplateContent, the Notifications Extensions Library, or XML strings. The resulting XmlDocument is then used to create a ToastNotification object that is then passed to the ToastNotifier.show method.

For example, here’s how Scenario 1 (js/scenario1.js) issues a toast using the toastText01 template (a value from the ToastTemplateType enumeration) through getTemplateContent:

var Notifications = Windows.UI.Notifications;

function displayToastUsingXmlManipulation(e) {
    // toastTemplateName is set according to the button you click

    var notificationManager = Notifications.ToastNotificationManager;
    var toastXml = notificationManager.getTemplateContent(
        Notifications.ToastTemplateType[toastTemplateName]);


    // Populate the XmlDocument in toastXml (code omitted)

    var toast = new Notifications.ToastNotification(toastXml);
    notificationManager.createToastNotifier().show(toast);
}

The following code from Scenario 3 (js/scenario3.js) demonstrates creating a toast with XML strings (toastImageAndText01). As with tiles, you can use ms-appx:///, ms-appdata:///local, or http:// URIs to refer to images (in-package, app data, and remote images, respectively):

function displayWebImageToastWithStringManipulation(e) {
    // toastTemplateName is set according to the button you click

    var notificationManager = Notifications.ToastNotificationManager;
    var toastXmlString;

    if (templateName === "toastImageAndText01") {
        toastXmlString = "<toast>"
                       + "<visual version='1'>"
                       + "<binding template='toastImageAndText01'>"
                       + "<text id='1'>Body text that wraps over three lines</text>"
                       + "<image id='1' src='" + urlBox.value + "' alt='" + altText + "'/>"
                       + "</binding>"
                       + "</visual>"
                       + "</toast>";
    } else {
        // Other cases omitted
    }

    var toastDOM = new Windows.Data.Xml.Dom.XmlDocument();
    toastDOM.loadXml(toastXmlString);
    var toast = new Notifications.ToastNotification(toastDOM);
    notificationManager.createToastNotifier().show(toast);
}

Butter and Jam: Options for Your Toast

Beyond the properties you can assign when creating a ToastNotification object (or a ScheduledToastNotification), there are additional bits you can include within the XML, as described in the Toast schema:

• The root toast element in the XML has optional launch and duration attributes. The launch attribute can be assigned a string that will be passed to the app’s activated handler as eventArgs.detail.arguments, exactly as happens with a secondary tile. (See “App Activation From a Secondary Tile” earlier in this chapter.) The duration attribute can have values of short (five seconds or the value from PC Settings > Ease of Access) or long (25 seconds or the value from PC Settings > Easy of Access, whichever is longer; refer back to Figure 13-7).

• The visual and binding elements in the XML can have branding and addImageQuery attributes that act exactly like their counterparts for tiles. Refer back to the “Branding” and “Using Local and Web Images” sections under “Tiles, Secondary Tiles, and Badges.” The image element also supports addImageQuery for scale, language, and contrast settings.

• The visual, binding, and text elements support a lang attribute to identify the current app language.

The toast element can also have a child audio element through which you can add a sound to a toast notification provided that the user has not disabled notification sounds altogether in PC Settings > Notifications. (Refer to Figure 13-8.) The particular sound is set with the src attribute and must be a one of the following string values as described in the Toast audio options catalog:68

ms-winsoundevent:Notification.Default

ms-winsoundevent:Notification.IM

ms-winsoundevent:Notification.Mail

ms-winsoundevent:Notification.Reminder

ms-winsoundevent:Notification.SMS

ms-winsoundevent:Notification.Looping.Alarm

ms-winsoundevent:Notification.Looping.Alarm2

ms-winsoundevent:Notification.Looping.Call

ms-winsoundevent:Notification.Looping.Call2

Separately, the audio.silent attribute controls whether audio plays at all (false, the default) or is muted (true). If the toast.duration attribute is set and you set audio.src to one of the latter four “Looping” sounds above, you can also set audio.loop to true (to repeat the sound) or false (to play the sound only once, the default).

Scenario 4 in the Toast notifications sample lets you play with the different notification sounds—different buttons choose different sounds. The text of each button (in a variable named toast-SoundSource) is appended to the ms-winsoundevent:Notification. as in this XML used to create the notification:

"<audio src='ms-winsoundevent:Notification." + toastSoundSource + "'/>"

Scenario 6 shows the use of the loop attribute in the XML as well:

"<audio loop='true' src='ms-winsoundevent:Notification.Looping.Alarm'/>"

Did you actually hear any sounds? When I first ran these samples, I sure didn’t! It took me a while to figure out why, so let me save you the trouble.

The values in the audio.src attribute simply map to various system sounds that are assigned in Control Panel > Hardware and Sounds > Change System Sounds, which displays the dialog box below. Having tired of all the beeps, boings, and dingalings that were once all the rage on personal computers, I routinely select the “No Sounds” option under Sound Scheme. As a result, there were no sounds assigned to anything in the Program Events list, so there were no sounds whatsoever for toast notifications. When I selected the Windows Default scheme, I then heard sounds with the toasts.

In short, the user does have ultimate control over the sounds, both generally in PC Settings and specifically in the dialog box below. So, if it’s appropriate to use a sound at all, just choose the one that’s closest to the nature of your toast and leave it at that.

Images

Tea Time: Scheduled Toasts

Issuing toasts from a running app is all well and good, but it’s not actually a common scenario because the user is already looking at the very same app. What’s more interesting are cases where the app isn’t necessarily running when a notification appears. This is why toasts are often used with push notifica-tions as well as background tasks, as we’ll see in the last two sections of this chapter, but the other means is a scheduled toast that will simply appear at some later time regardless of whether the app is running. This is a great way to invite the user to activate the app again.

A scheduled toast is created using Windows.UI.Notifications.ScheduledToast-Notification instead of the usual ToastNotification as we’ve been using. There are two forms of scheduled notification, as indicated by its pair of constructors:

ScheduledToastNotification(content, deliveryTime) Creates a one-time scheduled toast with the toast’s XmlDocument in content and the UTC DateTime when it should appear in deliveryTime.

ScheduledToastNotification(content, deliveryTime, snoozeInterval, maximumSnoozeCount) Creates a recurring scheduled toast whose content will appear at deliveryTime. If the toast is dismissed either explicitly or by letting it disappear on its own, it will continue to appear a total of maximumSnoozeCount times at intervals defined by the number of milliseconds in snoozeInterval. The snoozeInterval must be set between 60 seconds and 60 minutes; for longer intervals it’s best to just schedule separate toasts altogether.

A ScheduledToastNotification also has an id property, a maximum 16-character string that’s used to identify that toast. If you schedule a toast with the same id as an existing one, the new one will replace the old.

In all cases, the toast is scheduled by calling the ToastUpdater.addToSchedule method passing in the notification object. Here’s the process in code, as found Scenario 1 of the Scheduled notifications sample (js/scenario1.js), where toastDOM is the XmlDocument containing the content and dueTime is determined by a UI control in the sample. First, for a one-time notification:

var Notifications = Windows.UI.Notifications;

toast = new Notifications.ScheduledToastNotification(toastDOM, dueTime);
Notifications.ToastNotificationManager.createToastNotifier().addToSchedule(toast);

Second, for a notification that will repeat five times at 60-second intervals (the option that’s exercised if you check the Repeat checkbox in the sample’s UI):

var Notifications = Windows.UI.Notifications;

toast = new Notifications.ScheduledToastNotification(toastDOM, dueTime, 60 * 1000, 5);
Notifications.ToastNotificationManager.createToastNotifier().addToSchedule(toast);

To enumerate currently scheduled toasts, call ToastNotifier.getScheduledToast-Notifications. This returns a vector of ScheduledToastNotification objects, any of which can be canceled through ToastNotifier.removeFromSchedule. These methods are demonstrated in Scenario 2 of the Scheduled notifications sample that I will leave you to examine more closely. Also, there are some debugging tips on the Guidelines and checklist for scheduled notifications topic in the documentation, mostly to note that the system has a limit of 4096 total notifications and to make sure you’ve set Toast Capable in the manifest to Yes.

Toast Events and Activation

As far as toasts are concerned, we have perhaps saved the best topic for last! The whole purpose of a toast is to get the user’s attention and have them activate your app to take some kind of action. An app will commonly navigate to an appropriate page for whatever the content of the toast implies.

The most straightforward case of activation is with a scheduled toast or one that has been put up by a background task or through a push notification. In all of these cases the app won’t be running, so Windows will start it with the activation kind of launch, where the value of the toast.launch attribute will be in the activated event’s eventArgs.detail.arguments property. This is, once again, identical to the way secondary tiles work and you can process the arguments value however you wish.

If the app is not running when the toast is activated, it will still be launched even if the toast.launch attribute is empty. That is, toasts that occur under nonrunning conditions can be used to just launch the app, if desired. On the other hand, if a running app issues a toast with no toast.launch value, its activated event will not be fired at all. This is a way of saying that activation through a toast with no additional information would never cause the app to navigate in the first place, so what’s the point of firing the activated event? None whatsoever. Thus, if a running app issues a toast with the intent that activating that toast will switch to a different part of the app, a launch value is essential. (Of all the scenarios in the Toast notifications sample, only Scenario 5 provides a launch value; set a breakpoint in the activated event of js/default.js, and you’ll see that Scenario 5 is the only time that event will fire when you tap a toast.)

Still, a running app might want to know when the user interacts with a toast, launch arguments aside. For this purpose it can listen to a ToastNotification object’s activated, dismissed, and failed events, a few of which are demonstrated in Scenario 5 of the sample. The activated event has no specific eventArgs, but dismissed comes with a ToastDismissalReason in eventArgs.reason (values are userCanceled, applicationHidden, and timedOut), and the failed event comes with an error code in eventArgs.errorCode. (These are all events from a WinRT object, so be sure to manage them with removeEventListener as appropriate. See the section “WinRT Events and removeEventListener” in Chapter 3.)

Note that a ScheduledToastNotification does not support any of these events because the assumption is that the app probably won’t be running by that time anyway.

Push Notifications and the Windows Push Notification Service

We’ve now finally arrived in this chapter where we can leave running apps behind and look at more of the fun things that can happen behind the scenes. Earlier, in “Periodic Updates,” we learned that the shortest interval you can use with that method is pretty darn long by a computer’s reckoning: 30 minutes. That’s even long by many human standards, especially those of a user who really wants to know what’s happening with whatever information source your app is connected to.

To update a tile, set a badge, or issue a toast as quickly as the system allows, and to personalize the content (as with calendar reminders and email alerts), it’s necessary to be a little pushy and use push notifications. These are notifications that come to a system from an outside agent, typically a service that is monitoring some other source of information and detects a condition for which a notification is appropriate. We saw the mechanism in the “The Four Sources of Updates and Notifications” section and Figure 13-14 early in this chapter. To summarize:

• When launched, an app requests a channel URI for each of its live tiles and then sends those URIs to its associated web service. An app should do this each time it’s launched, as the expiration period for a WNS channel is 30 days.69 Each channel URI is unique for the user, the tile, and the device.

• The web service stores the channel URI and associates it with a user to customize their notification content (as again with email and calendar alerts, notifications from friends’ activities, etc.).

• When needed, the web service issues updates (XML payloads) to that channel.

• WNS then send the notification to the client devices where the app acquired the channel URI. Those notifications can update tiles, update badges, issue toasts, and update the lock screen (with appropriate lock screen apps and background tasks).

It’s also possible for the service and WNS to send what is called a raw notification, which can contain any payload you want: there just needs to be someone listening as Windows won’t know what to do with the data. A foreground app can listen through the PushNotificationChannel.onpush-notificationreceived event; a lock screen app can listen with a background task. In the latter case, raw notifications are generally used to deliver information to the background task and issues other notifications in response or updates app data.

Before you do anything in your app, however, you need to follow the instructions on How to authenticate with the Windows Push Notification Service (WNS) on the Windows Developer Center (which is part of a whole series on Sending push notifications). This will walk you through the steps on the Windows Store Dashboard to obtain a Package Security Identifier (SID) and a secret key that your web service must use to authenticate itself with WNS.

That done, let’s go through each of the steps in turn, using Scenarios 1–3 of the same Push and periodic notifications client-side sample we used earlier for periodic updates.

Note Because channel URIs are unique for an app+user+device, using push notifications can become an expensive proposition for your web service, which must record and maintain a channel for every unique tile on every user’s device and then figure out when to send which notifications to which channels. If your app becomes popular, this will require scaling up your service to potentially manage thousands or even millions of channel URIs. For this reason, seriously evaluate whether periodic notifications will be sufficient for your scenario, especially for updates that aren’t user specific, because they will be much simpler on the service side of the picture.

Requesting and Caching a Channel URI (App)

Requesting a channel URI is done through the Windows.Networking.PushNotifications.PushNotificationChannelManager object. This manager has only two methods: createPushNotificationChannelForApplicationAsync and createPushNotificationChannelForSecondaryTileAsync. The first is clearly linked to the app tile as well as toast notifications; the second is clearly for use with secondary tiles and takes a tileId argument to identify the specific one.

The result of both async operations is a PushNotificationChannel object that will be passed to your completed handler, as shown in Scenario 1 of the sample (start in js/scenario1.js, then go into js/notifications.js):

var channelOperation;

// Channel for the app tile
if (isPrimaryTile) {
    channelOperation = Windows.Networking.PushNotifications.PushNotificationChannelManager
        .createPushNotificationChannelForApplicationAsync();
} else {
    // Channel for a secondary tile
    channelOperation = Windows.Networking.PushNotifications.PushNotificationChannelManager
        .createPushNotificationChannelForSecondaryTileAsync(itemId);
}

channelOperation.done(function (newChannel) {
    // Send channel to web service
},  /* error handler */
);

The PushNotificationChannel object (newChannel in the code above) is a simple object with just a few members, but they are important ones:

expirationTime A read-only property indicating when the channel expires—notifications sent to this channel after expiration will be rejected. Apps must be sure to refresh their channels when needed to avoid an interruption in notifications.

uri A read-only URI to which the app’s web service sends notifications to WNS.

close A method that explicitly invalidates the channel.

pushnotificationreceived An event that’s fired when a notification is received on the client device from this notification channel. This will be fired only for apps that are in the foreground.

Your app should go through this short process to obtain the necessary channel URIs whenever it’s launched as well as when it’s resumed (especially if any channel’s expirationTime has passed). It’s unlikely that an app would stay suspended for that long, but it’s still possible! Furthermore, if you’re concerned that your app might not run for more than 30 days, you can implement a background task on a maintenance trigger for this purpose. See “Tasks for Maintenance Triggers” later in this chapter and Scenario 2 of the sample.

Again note that you may have more than one channel URI if you’re also using push notifications for secondary tiles as well as your app tile. In this case you’ll be managing a separate channel URIs for each tile.

Each time through the process, save the channel URI for each tile in your local app state. This is so that you can check on subsequent runs if the URI is the same as one you’ve already obtained and sent to your web service, in which case you can avoid unnecessary network traffic.

Sending the URI to your web service can be done with a simple call to WinJS.xhr, as in the sample (inside channelOperation.done). Here we also see the checks for whether the URI is the same as before:

channelOperation.done(function (newChannel) {
   // _urls[] is an array of channel ids for primary and secondary tiles
   var tileData = that._urls[itemId];

   // Upload the channel URI if the client hasn't recorded sending the same
   // uri to the server
   if (tileData && newChannel.uri === tileData.channelUri) {
      // This saves the URI to local app data
      that._updateUrl(url, newChannel.uri, itemId, isPrimaryTile);
      completed(newChannel);
   } else {
      WinJS.xhr({
         type: "POST",
         url: url,
         headers: { "Content-Type": "application/x-www-form-urlencoded" },
         data: "channelUri=" + encodeURIComponent(newChannel.uri) +
            "&itemId=" + encodeURIComponent(itemId)
      }).done(function (request) {

         // Only update the data on the client if uploading the channel URI succeeds.
         // If it fails, you may considered setting another background task, trying
         // again, etc. (An exception will be thrown if it fails, ending up in the
         // error hander instead.)
         that._updateUrl(url, newChannel.uri, itemId, isPrimaryTile);
         completed(newChannel);
      }, failed);
   }
}, failed);

Managing Channel URIs (Service)

If you use the code in the previous section, your web service that generates push notifications will receive HTTP POST requests with unique channel URIs for each and every tile. This isn’t the only way to transport channel URIs, of course; in fact, because a channel URI might be used to transmit personal information through notifications, it should ideally be encrypted with a private key before it’s sent to the server. Otherwise someone could possibly intercept that URI and use it to redirect user-specific notifications.

In any case, the service must expect to receive—and then manage—a unique URI for each app/user/device combination. This underscores the fact that push notifications are best used for user-specific notifications rather than broadcast notifications. In the latter case, setting up a service for periodic updates is a much easier solution.

Once the service receives a channel URI along with any data to identify the user and the purpose of the channel, it should securely save that information in persistent storage of some kind, such as a SQL Server database (for an ASP.NET service) or a MySQL (for a PHP service).

It’s important that the service also removes obsolete channel URIs. If it receives a new URI for the same user and the same purpose, it should replace the old with the new. It should also remove any URIs from its data store if it receives an HTTP 404 or 410 error back from WNS, indicating an obsolete channel.

A simple ASP.NET service page that can receive a post from Scenario 1 of the Push and periodic notifications client-side sample can be found in the HelloTiles website project in this chapter’s companion content, specifically receiveuri.aspx. To run this service, make sure you have the localhost established, as described earlier in the “Using the localhost” section for periodic updates. You may also need to install ASP.NET on your localhost. An easy way to do this is to obtain the Background transfer sample, go into its Server folder, and then from an administrator command prompt run powershell -ExecutionPolicy unrestricted -file serversetup.ps1. If you then run the site in Visual Studio Express 2012 for Web as we did before, you should have a localhost port for the service (for instance, http://localhost:52568/HelloTiles/receiveuri.aspx).

You can then set a breakpoint in the service code, paste the service URI into Scenario 1 of the Push notifications sample, and press its Reopen Channel And Send To Server button. This should hit the breakpoint in the service and allow you to step through the code that processes the request. Here you’ll find that the request contains channelUri and itemId values (along with LOGON_USER), which can be saved for when the service needs to send a notification to WNS. Something similar can be written in other server-side languages, of course, and a great place to find tools to help with writing services is the Windows Azure Toolkit.

Sending Updates and Notifications (Service)

Before a service can send updates, it must to authenticate itself with WNS by sending the Package Security Identifier (SID) and client secret as obtained through the Windows Store Dashboard. This is a matter of sending an XmlHttpRequest to WNS (via HTTPS) that looks like this:

POST /accesstoken.srf HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: https://login.live.com
Content-Length: 211
grant_type=client_credentials&client_id=ms-app%3a%2f%2fS-1-15-2-2972962901-2322836549-3722629029-13452385
79-3987825745-2155616079-650196962&client_secret=Vex8L9WOFZuj95euaLrvSH7XyoDhLJc7&scope=notify.windows.co
m

where you must make sure the values of client_id and client_secret match the package SID and client secret. If the authentication works, you’ll receive a 200 OK response with the access token you need for sending notifications:

HTTP/1.1 200 OK
Cache-Control: no-store
Content-Length: 422
Content-Type: application/json
{
    "access_token":"EgAcAQMAAAAALYAAY/c+Huwi3Fv4Ck10UrKNmtxRO6Njk2MgA=",
    "token_type":"bearer"
}

Code that accomplishes these steps for a service written in C# can be found on How to authenticate with the Windows Push Notification Service, where your service would use the GetAccessToken method shown there to obtain an OAuthToken object with the information from the response. Services written in other languages will obviously need to use the appropriate means to send the request and receive the response.

Whatever the case, once you have the access token you’re ready to start sending updates and notifications via XmlHttpRequests to the channel URIs maintained by the service.

For tile updates, badge updates, and toast notifications, sending a notification means generating the XML payload as for any other update or notification, and then sending it to WNS with the previously acquired access token. The only real difference between these requests, besides the specific XML, is the value of X-WNS-Type in the request header: wns/badge, wns/tile, wns/toast, or wns/raw (see the next section). Otherwise the code is the same.

Generic code for a C# service can be found on Quickstart: Sending a tile push notification and Quickstart: Sending a toast push notification. I’ve included a badge update version in sendBadgeToWNS.aspx in the Hello Tiles example site with this chapter, where the SID and client secret are ones I obtained for the Push notifications sample. (You may need to re-create those yourself.) To test all this, run the Hello Tiles website in Visual Studio Express 2012 for Web and set a breakpoint at the beginning of sendBadgeToWNS.aspx. Assuming you’re running Scenario 1 of the Push notifications sample in Visual Studio Express 2012 for Windows 8 to upload a channel URI to receiveuri.aspx, there should be a file called channeluri_aspx.txt in the website project that contains the uploaded data.

Now switch to Scenario 3 of the Push Notifications sample and press the button to start listening to the pushnotificationreceived event. In js/scenario3.js of that sample, set a breakpoint within the pushNotificationReceivedHandler function. With all this in place, open a browser and enter the address of sendBadgeToWNS.aspx on the localhost: http://localhost:52568/HelloTiles/sendBadgeToWNS.aspx, for example. This should hit the breakpoint in Visual Studio Express 2012 for Web, where you can walk through that page’s code and see it loading the channel URI from channeluri_aspx.txt, to which it then sends a badge update. When that happens, you should hit the breakpoint in the Push notifications app where you can walk through that code. Note that when you get to the line e.cancel=true, skip over it—right-click the line below it and select Set Next Statement. This will allow Windows to process the notification and update the badge for the Push notifications sample, which should now look like the following with a * badge on the lower right:

Images

Note again that if you receive an HTTP 404 or 410 error back from WNS, the channel URI is no longer valid and you should remove it from your list. It’s also good for the app to notify your service whenever it no longer needs updates for a particular channel (no point in paying for unproductive bandwidth). And if WNS returns an error, avoid posting the update again unless it makes sense for your scenario.

A 404 or 410 error is different, by the way, from an inability to deliver to notification because the client is offline. In this case WNS will cache the tile, badge, or raw notification until the client reconnects. In other words, it’s not a condition that your service has to worry about. Send notifications as you always would, and let WNS handle the delivery details.

Raw Notifications (Service)

If you use wns/raw as the push notification type, the payload included with the push notification can be anything you want, not just XML, as long as it’s under 5KB. Of course, Windows cannot do anything with this payload directly, so an app has to provide a handler for receipt of the notification, as the next section explains.

Receiving Notifications (App)

A running app receives push notifications through the PushNotificationChannel.onpush-notificationreceived event. This is again required to process wns/raw payloads but can be used for any type. If the app is not running, of course, it won’t receive this event. Instead, the app must be on the lock screen with a PushNotificationTrigger background task for this purpose. (See “Lock Screen Dependent Tasks and Triggers” later in this chapter.) That piece of code will then receive the XML payload, process it, and issue whatever tile updates, badge updates, or toast notifications are necessary. Besides saving some state to the app data folders, this is really all that the background task can do, but it’s enough to keep that sense of aliveness going as well as invite the user to launch the app in response.

In the running app, the pushnotificationreceived event is fired for the other notification types as well. Scenario 3 of the sample shows this in its event handler—I’ve modified this code a little bit for simplicity:

function startListening() {
    // Assume channel has been obtained and validated
    channel.addEventListener("pushnotificationreceived", pushNotificationReceivedHandler);
}

function pushNotificationReceivedHandler(e) {
    // Extract notification payload for each notification type

    var notificationPayload;
    switch (e.notificationType) {
        case pushNotifications.PushNotificationType.toast:
            notificationPayload = e.toastNotification.content.getXml();
            break;

        case pushNotifications.PushNotificationType.tile:
            notificationPayload = e.tileNotification.content.getXml();
            break;

        case pushNotifications.PushNotificationType.badge:
            notificationPayload = e.badgeNotification.content.getXml();
            break;

        case pushNotifications.PushNotificationType.raw:
            notificationPayload = e.rawNotification.content;
            break;

    }

    // Process the notification: set e.cancel to true to suppress automatic handling.
}

The last bit in the comment above is important. When you receive this event in a running app, it wouldn’t be necessary to display a toast unless it pertains to some other part of the app that isn’t visible. For example, if you have an app that handles both email and a calendar, you might want to show email toasts when the user is looking at the calendar and calendar toasts when the user is looking at email. In this case, setting e.cancel to true will suppress the toast.

With the pushnotificationreceived event, the running apps gets first crack at raw notifications. If the app doesn’t process it, the notification will be sent to any lock screen background task configured for the PushNotificationTrigger. In either case, refer to the Raw notifications sample for more details.

Debugging Tips

When using push notifications, experience shows that if notifications aren’t getting through, it’s typically not a problem with WNS. Here’s a list of things to check (thanks to Hans Andersen for this list):

• Check the return status of your HTTP POSTs to WNS. If it’s returning an HTTP 200 response, check the X-WNS-NotificationStatus and other headers you get back. Look particularly for the status of “Received,” which indicates that a notification has gone to the client.

• Lacking anything conclusive in the headers, run Event Viewer and check the events under Application And Services Logs > Microsoft > Windows > Push Notifications Platform > Operational to see the activity.

• Also look under Application And Services Logs > Microsoft > Windows > Immersive-Shell > Microsoft-Windows-TWinUI > Operational to see if there are error messages related to XML parsing about the same time you expected to receive a notification.

• Even if the XML is well-formed, an update might not show up if a referenced image is either too large (pixel dimensions or file size), if the image is the wrong format (for example, TIF), if the image is corrupt, if the server handling the image request can’t handle the query parameters for the tile (scaling, contrast, language), or if the server is encountering other errors as might be revealed in its own logs.

• If updates appear but after a considerable delay, it could just mean internal timeouts or other network latency within the tile and notification infrastructure. If this happens, just accept that the world isn’t always perfect and operations must sometimes be retried!

Windows Azure Toolkit and Windows Azure Mobile Services

Clearly, plenty of work is involved to create a service capable of receiving channel URIs and sending notifications through WNS. Recognizing this, the Windows Azure Toolkit once again provides some solutions. Going into all the details is beyond the scope of this book, but the link above will get you started. More specifically, check out the Azure Notifications Samples and the Raw Notifications Sample, as well as the Push Notification Worker sample. There is also a helpful video on the Channel 9 site: Episode 73 – Nick Harris on Push Notifications for Windows 8. Additional resources have likely been published since this chapter was written, so a quick Internet search will likely turn up more.

Also check out Windows Azure Mobile Services, which helps you create a scalable backend for an app, including structured cloud data, authentication, and push notifications. This is quite new as of the time of writing, so I don’t have links to other resources, but it’s certainly worth looking into.

Background Tasks and Lock Screen Apps

At the end of the introduction to this chapter, I described how everything we’ve talked about so far helps to “create an environment that is alive with activity while those apps are often not actually running or are allowed to run just a little bit.” It’s that last phrase—being allowed to run just a little bit through background tasks—that is our last topic for this chapter. And as described earlier as well, background tasks are related to the lock screen because the apps that are allowed to work on the lock screen must also employ certain background tasks.

Let me reiterate here that we’ve already seen a number of scenarios in which the user can experience app-related activity without the app having to run. Periodic tile updates, push notifications, scheduled toasts, and even sharing data through the Share contract all provide for activity when an app is suspended or not running. Apps can also configure background data transfers to occur while the app isn’t running, as we’ll see in Chapter 14, “Networking.” And background audio provides for that specific class of apps that need to continue running to maintain VoIP sessions, audio playback, online meetings, and so forth.

What’s left in the story are those little pieces of app code that Windows can run in response to specific triggers. Triggers in some cases can be further refined with optional conditions so that the background task runs only when it really needs to. This is all to minimize the amount of background activity that can drain a device’s battery. Some types of triggers, in fact, require that the user has placed the app on the lock screen to specifically limit the number of apps that can respond to those triggers. Furthermore, Windows also limits the amount of CPU time that background tasks can consume:

Lock screen background tasks Two seconds of cumulative CPU time per 15 minutes.

Other background tasks One second of cumulative CPU time every two hours.

Consumption of network bandwidth is also limited on battery power. What that limit is, exactly, I cannot say, because the system analyzes energy usage more so than bytes transferred. A means of estimating the limit can be found on Supporting your app with background tasks. (While we’re at it, you might also be interested in Guidelines and checklists for background tasks, the Introduction to background tasks whitepaper, and Being productive in the background – background tasks on the Windows Blog.)

“Whoa!” you’re probably saying, “Is Windows 8 really that restrictive?”

The short answer is yes, because Windows not only wants to save battery power for the foreground app with which a user is engaged, but also wants to make sure the foreground app delivers the best user experience. This means it isn’t having to complete with background apps that would, if allowed, take up as many resources as they possibly can. (Developers of background services will always find a justification for hogging up resources!)

It’s likely that you’ve experienced situations like this directly, where you’ve started an app but it takes for-EV-er to start up because some other dark and mysterious services is chewing on the hard drive, pounding the network, flaring up the CPU, and so forth. I, for one, have dug through Task Manager and the Resource Monitor to figure out—and kill off—whatever process is pouring molasses on my system, let come what will. This is the kind of user experience that Windows 8 is trying to avoid.

“OK,” you say (assuming that I’ve actually convinced you to some small degree), “does that mean that there isn’t any way to do some background work like indexing data, creating picture thumbnails, processing video, and so on?”

Actually, there are ways to do this. For one, when an app is in the foreground, it can do however much it wants of all these things because it’s ultimately responsible for its own user experience. (An app written in JavaScript can, for such purposes, employ web workers to move such work off the UI thread, as well as delegate tasks to WinRT components that do their work on other threads and return results asynchronously. We’ll look at this in Chapter 16.)

Second, when a device is on AC power instead of battery, Windows allows apps to run background tasks in response to maintenance triggers on 15-minute or longer intervals (whatever is appropriate for the app). These are still limited in the total amount of CPU time they can consume, but tasks that don’t involve UI—which background tasks are not allowed—can burn through a few billion instructions in one or two seconds on a gigahertz CPU!

What we have in this whole story, then, are three distinct classes of background tasks and their associated triggers:

• Tasks for maintenance triggers that run on AC power only

• Tasks for potentially conditioned system triggers that run on AC or battery and don’t require being on the lock screen

• Tasks for those privileged apps that the user had added to the lock screen

We’ll look at each of these in detail in the sections that follow, but first there are a few aspects that are shared by them all: declaring background tasks in the manifest, the general process of building the task with the WinRT API, and conditions.

Background Tasks in the Manifest

All background tasks for an app are declared in the manifest, where each declaration indicates the type of task as well as the code to execute for that task, as shown in Figure 13-18. We’ve seen this section of the manifest before in Chapter 10 where we checked Audio for a background audio app. As for the other options, System Event is used for the first two classes of background tasks in the list above, and Control Channel, Timer, and Push Notification are specifically for tasks reserved for lock screen apps.

Images

FIGURE 13-18 The manifest editor for declaring background tasks, showing the option for Background Tasks in the drop-down list of Available Declarations (left), the background task types (center), and the Start Page field to indicate the JavaScript code to run for the task (bottom). Background tasks can also be written in other languages, in which case the Executable and Entry Point fields are used.

In all cases, the Start Page field is where you indicate the JavaScript file to execute for the task, but do note that because background tasks execute independently of the app itself, sharing state only through app data, you can really choose whatever language you want. Given the quotas on CPU time, writing a background task in a language like C++ or C# will allow you to do some tasks more efficiently, in which case you’ll use the Entry Point field (if the task is in a DLL in the package) and perhaps the Executable field (if the task is an another EXE in the package) to identify the code module and specific function to call.

It’s also good to note that even though the Start Page field for JavaScript suggests a page, it’s really just code that you use for a background task—you’ll get an error if you try to specify an HTML file here. (To be more specific, a background task in JavaScript is a web worker, plain and simple.) Such is why you can’t do UI from a background task: you can’t have Windows load any HTML or CSS, just JavaScript! Thus, issuing tile updates, badge updates, and toasts is as much UI work as a task is allowed. For anything else, the background task must write values to app data that the main app can pick up within its handlers for background task events, as we’ll see shortly.

You might also notice that the System Event option in the manifest editor doesn’t offer another field in which you indicate the task’s specific trigger—this is done in code when we build the task, as we’ll see next.

Building and Registering Background Task

The declaration of a background task in the manifest is only that—a declaration that tells the system that the app intends to use a background task. The app must still register the background task from code in order for it to execute at all, which is accomplished using the Windows.ApplicationModel.-Background.BackgroundTaskBuilder (whose parent namespace contains everything we’ll be referring to in the context of background tasks). Simply said, you create an instance of the builder, set its name and taskEntryPoint properties, call its setTrigger and addCondition methods to specify exactly when the task should run, and then call register.

Generic code for this is found in the Background task sample within js/global.js. This module declares a global object BackgroundTaskSample that contains a number of properties and methods. The one that concerns us here is a method called registerBackgroundTask that registers a given entry point (the name of a JavaScript file or the name of a class in C#, Visual Basic, or C++), with a given name, and applying some trigger and condition:

var BackgroundTaskSample = {
    // Properties with names and entry points of the sample's tasks are omitted

    //
    // Register a background task with the specified taskEntryPoint, taskName, trigger,
    // and condition (optional).
    //
    "registerBackgroundTask": function (taskEntryPoint, taskName, trigger, condition) {
        var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();

        builder.name = taskName;
        builder.taskEntryPoint = taskEntryPoint;
        builder.setTrigger(trigger);

        if (condition !== null) {
            builder.addCondition(condition);
        }

        var task = builder.register();
        BackgroundTaskSample.attachProgressAndCompletedHandlers(task);

        // [Sample-specific code omitted]

        // Remove previous completion status from local settings.
        var settings = Windows.Storage.ApplicationData.current.localSettings;
        settings.values.remove(taskName);
    },

In this code, the BackgroundTaskBuilder.register method returns a BackgroundTask-Registration object through which you manage a registered task. A registered task will have a name property and a system-assigned taskId property, the latter of which you can use to store app data that’s unique to the task. It also has an unregister method, which you would call for obvious purpose, and two events: completed and progress. Handlers for those events are assigned in the usual manner with addEventListener, as seen within the BackgroundTaskSample.attach-ProgressAndCompletedHandlers function in the sample:

"attachProgressAndCompletedHandlers": function (task) {
    task.addEventListener("progress",
        new BackgroundTaskSample.progressHandler(task).onProgress);
    task.addEventListener("completed",
        new BackgroundTaskSample.completeHandler(task).onCompleted);
},

One of the key uses of these handlers is to perform UI update tasks in response to data left behind by the background tasks. Those tasks themselves cannot work with UI, but they can save data to the app data areas that they share with the main app. The completed and progress events, then, are how the main app—the one that can work with the UI—can pick up those events from the background task to read values from app data and do the necessary updates. The Background task sample does this in each of its scenarios.

There is also one static property, BackgroundTaskRegistration.allTasks, an IMapView through which you can retrieve your registered tasks and obtain the specific BackgroundTask-Registration object for each.

It’s very important to note that Windows allows you to register the same background task twice and will assign unique taskId values to both, so be careful to avoid duplicate tasks. Notice too how the registerBackgroundTask code above makes a little use of the local settings container in app data. This is how the app communicates with each of its independent tasks because app data is the only means for such data exchange.

With this structure, the question now becomes: what do we provide for the triggers and the conditions? The answer is what differentiates the various kinds of background tasks.

Conditions

The specific conditions you can specify through BackgroundTaskBuilder.addCondition are instances of the SystemCondition class. A background task registered with one or more conditions—each call to addCondition is cumulative—will run only if the conditions are met. Each instance can be one of the following types as defined in the SystemConditionType enumeration: internetAvailable, internetNotAvailable, sessionConnected (the user is logged in), sessionDisconnected (the user is logged out), userPresent (the user has been recently active), and userNotPresent (the user has not been active for a time).

Clearly, each pair of these conditions is mutually exclusive: if you register a task with internet-Available and internetNotAvailable, Windows will recognize that you never really wanted to run the task in the first place, so it will let it sit on the roadside, forever undisturbed! Otherwise, you can use these to make sure that your task is run only when needed. If you want to execute a background task that renews push notification channels, for example, there’s no point in trying if there’s no connectivity. (We’ll see an example in the next section, “Tasks for Maintenance Triggers.”) On the other hand, if you have a background task that you want to make sure never interferes with the overall user experience, you can add the userNotPresent condition.

Note that because the sessionDisconnected condition implies that the user has logged out, it’s useful only for background tasks that require the lock screen.

Tasks for Maintenance Triggers

Background tasks that use a maintenance trigger are probably the most generic kind of task—they’re really just any kind of code you want to run every now and then when the system is on AC power.70 Such tasks are best for “checking up on something” or other activity that you want to run periodically but don’t really care when. As such, maintenance triggers aren’t appropriate for something like synchronizing data with a server because that should happen in a more timely manner and is best done with the background transfer API that we’ll see in Chapter 14.

A maintenance trigger—what you pass to BackgroundTaskBuilder.setTrigger—is an instance of the MaintenanceTrigger class. When creating the instance, you provide two parameters. The first is basically the refresh period you need (the freshnessTime property, in minutes), and you should always use the longest period that’s reasonable for your scenario; the system will always wait at least this long before first running the task. The second parameter is a flag that indicates if the task needs to be run only once (the oneShot property).

Scenario 2 of the Push and periodic notifications client-side sample demonstrates using a maintenance trigger to periodically refresh its WNS channels, as described earlier in “Requesting and Caching a Channel URI.” The code here is condensed from js/scenario2.js, some of which is in an internal function called registerTask:

var background = Windows.ApplicationModel.Background;
var pushNotificationsTaskName = "UpdateChannels";
var maintenanceInterval = 10 * 24 * 60; // 10 days

var taskBuilder = new background.BackgroundTaskBuilder();
var trigger = new background.MaintenanceTrigger(maintenanceInterval, false);
taskBuilder.setTrigger(trigger);
taskBuilder.taskEntryPoint = "js\\backgroundTask.js";
taskBuilder.name = pushNotificationsTaskName;
var internetCondition = new
    background.SystemCondition(background.SystemConditionType.internetAvailable);
taskBuilder.addCondition(internetCondition);

taskBuilder.register();

Because the expiration period for channel URIs is 30 days, the sample creates a trigger on a recurring 10-day interval (10 days * 24 hours/day * 60 minutes/hour). It also wisely adds the internetAvailable condition because it’s again pointless to attempt to renew channel URIs when there’s no connectivity.

The task itself can be found in the js/backgroundTask.js file of the sample, as indicated in the taskEntryPoint property:

(function () {
    // Import the Notifier helper object
    importScripts("//Microsoft.WinJS.1.0/js/base.js");
    importScripts("notifications.js");

    var closeFunction = function () {
        close();
    };

    var notifier = new SampleNotifications.Notifier();
    notifier.renewAllAsync().done(closeFunction, closeFunction);
})();

This task code pulls in a couple of other script files using importScripts, the second of which, notifications.js, is the sample’s set of helper functions for notifications where renewAllAsync refreshes the app’s list of previously saved channel URIs.

Important You’ll also notice that the completed and error handlers given to the promise from renewAllAsync both go to closeFunction, which makes this mysterious call to close. What close is this? Well, it’s not window.close (as you might guess) but rather WorkerGlobalScope.-close. Background tasks in an app written in JavaScript run within the scope of a web worker, so the global scope within the code is WorkerGlobalScope rather than window. Calling this makes sure the independently running background task is shut down and guarantees that the resources that were allocated for the task are properly released.

Within a JavaScript background task, the Windows.UI.WebUI.WebUIBackgroundTask-Instance.current contains a WebUIBackgroundTaskInstanceRuntimeClass object that provides additional details about the running task: its instanceId, its associated Background-TaskRegistration object in the task property, a progress property in which the task can store a percentage value, a succeeded flag to indicate that the task has completed, a suspended count (when the task is suspended due to the resource quota being exceeded), and a canceled event that informs the task that the app as a whole has been terminated.

This object also provides a getDeferral method that, once again, returns a deferral object whose completed method you call when the task is complete. As always, you employ the deferral if you need to perform asynchronous operations within the background task. Just be sure to always call close when everything is finished.

Tasks for System Triggers (Non-Lock Screen)

The next class of background tasks contains those tied to a variety of system triggers, specifically instances of the SystemTrigger class. You again create the trigger object with new and pass two parameters: a SystemTriggerType value (available afterwards as the triggerType property) and a oneShot Boolean flag. The triggers that operate independently of the lock screen are described in the following table:

Images

The Background task sample provides a few examples of these triggers. In Scenario 1, js/sample-background-task-with-condition.js, we can see the use of timeZoneChange along with the userPresent condition (where BackgroundTaskSample is again a helper object in global.js):

BackgroundTaskSample.registerBackgroundTask(BackgroundTaskSample.sampleBackgroundTaskEntryPoint,
    BackgroundTaskSample.sampleBackgroundTaskWithConditionName,
    new Windows.ApplicationModel.Background.SystemTrigger(
        Windows.ApplicationModel.Background.SystemTriggerType.timeZoneChange, false),
    new Windows.ApplicationModel.Background.SystemCondition(
        Windows.ApplicationModel.Background.SystemConditionType.userPresent));

This is clearly a case where I’d use another variable to not type the Windows.Application-Model.Background namespace out every time, but at least you can’t make a mistake in reading this code! In any case, the same sample, in Scenario 4 and js/global.js, also shows use of the servicing-Complete trigger within a helper function registerServicingCompleteTask, which also checks if the task is already registered:

"registerServicingCompleteTask": function () {
    // Check whether the servicing-complete background task is already registered.
    var iter =
        Windows.ApplicationModel.Background.BackgroundTaskRegistration.allTasks.first();
    var hascur = iter.hasCurrent;
    while (hascur) {
        var cur = iter.current.value;
        if (cur.name === BackgroundTaskSample.servicingCompleteTaskName) {
            BackgroundTaskSample.updateBackgroundTaskStatus(
                BackgroundTaskSample.servicingCompleteTaskName, true);
            return;
        }
        hascur = iter.moveNext();
    }

    // The servicing-complete background task is not already registered.
    BackgroundTaskSample.registerBackgroundTask(
        BackgroundTaskSample.servicingCompleteTaskEntryPoint,
        BackgroundTaskSample.servicingCompleteTaskName,
        new Windows.ApplicationModel.Background.SystemTrigger(
            Windows.ApplicationModel.Background.SystemTriggerType.servicingComplete, false),
        null);
},

In the sample, the tasks associated with these triggers are implemented in C#, within a WinRT component found in the Tasks project of the sample’s solution. I won’t show the code here because we’ll be looking at the general structure of WinRT components in Chapter 16. What it does demonstrate, though, is that you can use a mixed-language approach for background tasks. In these cases, the Entry Point field for the tasks in the manifest point to the C# class/method that implements the background task, such as Tasks.ServicingComplete. If you go to the Background task sample page, you can also download the C# and C++ versions of the sample to see even more structural variants.

Lock Screen–Dependent Tasks and Triggers

The last group of background tasks are those that require the app is also added to the lock screen. For this there are four applicable SystemTrigger options from SystemTriggerType, along with the three other distinct types that are represented in the manifest editor: TimeTrigger, and PushNotificationTrigger, and Windows.Networking.Sockets.ControlChannelTrigger. These are described in the following table along with pointers to available samples that demonstrate their usage:

Images

Images

Note Working with the lock screen is not supported in the Visual Studio simulator. To debug lock screen apps and background tasks, you’ll need to use the Local Machine or Remote Machine debugging options.

Background tasks for these triggers are created and registered as we’ve already seen. A TimeTrigger, for example, is created with its freshnessTime interval (in minutes) and a oneShot flag, as seen in Scenario 5 of the Background tasks sample (js/time-trigger-background-task.js):

BackgroundTaskSample.registerBackgroundTask(
    BackgroundTaskSample.sampleBackgroundTaskEntryPoint,
    BackgroundTaskSample.timeTriggerTaskName,
    new Windows.ApplicationModel.Background.TimeTrigger(15, false), null);

A TimeTrigger is also used in Scenario 3 of the Geolocation sample to allow the user to add a navigation app to the lock screen for more continuous tracking. Generally speaking, though, a navigation app isn’t particularly useful on the lock screen in the first place, since it wouldn’t be able to show a map! Better, then, to again use the Windows.System.Display.DisplayRequest API to prevent going to the lock screen at all.

Creating a PushNotificationTrigger is even simpler as there are no parameters. This can be seen in the Raw notifications sample, Scenario 1 (js/scenario1.js):

function registerBackgroundTask() {
    // Register the background task for raw notifications
    var taskBuilder = new background.BackgroundTaskBuilder();
    var trigger = new background.PushNotificationTrigger();
    taskBuilder.setTrigger(trigger);
    taskBuilder.taskEntryPoint = sampleTaskEntryPoint;
    taskBuilder.name = sampleTaskName;

    var task = taskBuilder.register();
    task.addEventListener("completed", backgroundTaskComplete);
}

Although the call to BackgroundTaskBuilder.register might succeed, the task itself will not execute until the user add the app to the lock screen, as we saw earlier in Figure 13-10. This latter action is never under the app’s control—all it can do is make sure it’s available for the user to select on that section of PC Settings, which is what asking for access is all about.

The request is made through the method Windows.ApplicationModel.Background.-BackgroundExecutionManager.requestAccessAsync; this call should be made prior to registering the background task (see Scenario 5 of the Background task sample again):

Windows.ApplicationModel.Background.BackgroundExecutionManager.requestAccessAsync();

When this is called the first time in an app, it will generate a user consent prompt, as shown in Figure 13-19. If the user chooses Allow, the app will appear in PC Settings as an option for the lock screen, otherwise it won’t. As with other permissions, users can change their minds later on through the Permissions settings, as shown in Figure 13-20.

Images

FIGURE 13-19 The user consent prompt when an app requests lock screen access.

Images

FIGURE 13-20 The lock screen option on the Permissions settings panel for apps that request access.

For a complete demonstration, refer to the Lock screen apps sample. In Scenario 1 it shows how to again request access to the lock screen and check the result, which is a value from the Background-AccessStatus enumeration. It also shows querying for and removing that access with the getAccessStatus and removeAccess methods of BackgroundExecutionManager.

Scenario 2 then demonstrates sending badge updates to the lock screen, along with a text tile update if the app happens to be the single one selected for that privilege. There is nothing particular in this process where the lock screen is concerned, however: such updates happen exactly as they do for the primary app tile. It’s just that those updates are also reflected on the lock screen. In the case of badges, the badge glyph will appear along with the app’s Badge Logo in the Application UI > Notifications section of the manifest. (Refer back to Figure 13-10.) To repeat from earlier, this graphic must have white or transparent pixels, and the three scale sizes are 24x24 (100%), 33x33 (140%), and 43x43 (180%).

Scenario 3, finally, demonstrates that secondary tiles can be added to the lock screen as well, irrespective of the app tile. To make a secondary tile available for the lock screen, assuming that the app has requested lock screen access already, you need to set those two properties of Windows.UI.-StartScreen.SecondaryTile that we mentioned long ago: lockScreenBadgeLogo and lockScreenDisplayBadgeAndTileText. If the secondary tile is on the Start screen, these properties will also make it available on the PC Settings page for the lock screen.

Debugging Background Tasks

By this time you might have run the TimeTrigger background task in Scenario 5 of the Background tasks sample, and unless it’s been more than 15 minutes since that time (maybe up to 30 minutes if you just missed the 15-minute window when timers are coalesced), you might still be waiting for that period to elapse. Is this, then, your destiny for debugging background tasks: to wait, wait, wait?

Fortunately, the answer is no, no, and maybe! That is, Visual Studio’s debugger is mostly aware of registered background tasks and provides a list of them on the Suspend drop-down menu on the toolbar:

Images

Selecting one of these will immediately trigger the background task, so you won’t have to wait or otherwise attempt to activate the trigger for real. One caveat is that if the trigger had oneShot set to true and already fired, it won’t fire again. A second caveat with this is that if you’re running a JavaScript app with background tasks written in other languages, you’ll need to change the debugger type for the main app project from Script Only to one that supports Managed or Native as shown here, otherwise you can’t set breakpoints in those other modules:

Images

A third caveat is that background tasks using ControlChannelTrigger, PushNotificatio-nTrigger, and the SystemTriggerType.SmsReceived will not appear on the Visual Studio drop-down menu.

So you might need to rely on the tried-and-true methods of outputting diagnostic information to figure out what’s going on with your task and checking events in the Event Viewer for activation failures. More on these methods can be found on How to debug a background task.

Finally, note one more time that background tasks are not supported in the Visual Studio simulator, as is also true of live tiles, notifications, and much else that we’ve covered in this chapter. You’ll need to use the Local Machine or Remote Machine options instead.

What We’ve Just Learned (Whew!)

• Tile updates, on both the app’s primary and secondary tile, along with badges, toast notifications, and background tasks—from which an app can issue tile updates and notifications—are how an app contributes to the overall aliveness of the system even while the app isn’t running.

• Tile updates and notifications can be sent from a running app, of course, but there are other methods to deliver those updates when the app isn’t running. Updates can be scheduled to appear at a later time, and the app can configure the system to periodically ask a service for tile/badge updates. Apps can also configure push notifications that are raised from a web service and sent to clients through the Windows Push Notification Service (WNS).

• Tile updates are issued using an XML payload based on predefined templates. Typical payloads include both square and wide tile updates so that the user can choose how the tile is displayed. The XML can reference images from both local and remote sources, so long as the images are 1024x1024 pixels or smaller and less than 200KB in size.

• A tile can cycle through up to five updates at any given time, each of which can be replaced separately.

• Apps that have specific content that is interesting to bookmark as secondary tiles to the Start screen provide Pin and Unpin commands to the user for that purpose. Secondary tiles, which launch the app with specific startup arguments, can also receive live tile updates.

• Badges are small glyphs or numbers that can appear on any given tile. Badge updates are sent through the same mechanism as tile updates, but they operate independently.

• Toasts are popup notifications that appear for a time to alert the user of new information, reminders, and so on. They can be configured to play sounds, set to recur on a given interval, and scheduled to appear in the future. Like secondary tiles, activating a toast launches the app with specific startup arguments.

• Periodic updates for tiles and badges means providing Windows the URIs of web services to call at selected intervals between 30 minutes and 24 hours. Periodic updates are the easiest and lower-cost means to update a tile from a running web service.

• Push notifications for tiles, badges, toast notifications, and raw notifications (whatever data an app wants to manage) can be used for higher-frequency, user-specific updates. This involves creating web services that communicate with WNS to issue those notifications to specific channel URIs, a process that is much more involved and expensive than periodic updates.

• Background tasks are small pieces of code that an app configures to run when certain triggers occur, such as changes in connectivity, timers, receipt of push notifications, and app updates. Apps should never depend on background tasks, however, because they are always under the user’s control.

• Background task triggers can be refined through specific conditions to avoid running tasks when it’s not necessary (such as when there is no connectivity).

• Some triggers require that the app has also been added to the lock screen. Such apps must first request access, which is subject to user consent, and the user must specifically add the app through PC Settings. Given that privilege, apps can issue badge updates and tile text to the lock screen.

• Through maintenance triggers, apps can also set up tasks to run periodically when a device is on AC power.