Time Tortoise: Working Around UWP Limitations

UWP 669

This is one in a series of articles about Time Tortoise, a Universal Windows Platform app for planning and tracking your work schedule. For more on the development of this app and the ideas behind it, see my Time Tortoise category page.

I decided to use the Univeral Windows Platform for Time Tortoise because I’m targeting Windows, and because UWP is the direction that the Windows user interface is moving (as of 2017). However, I knew from the beginning that UWP would not have all of the functionality of more established options like Windows Presentation Foundation. So as I make design decisions, I also look for ways to avoid getting stuck due to UWP limitations.

Types of UWP Limitations

UWP limitations come in two main categories. First, there are limitations that result from its relative newness. These are temporary limitations that have a reasonable chance of being rectified as the UWP and .NET teams add missing functionality. An example: code coverage for UWP unit tests. This has been requested for a few years and still isn’t supported. But since code coverage is a core feature of Microsoft unit testing technologies, it seems reasonable to assume that it will eventually show up.

The other category of UWP limitations is related to UWP’s core purpose as a sandboxed runtime that prevents malicious code from causing trouble on a machine. Limitations in this category are inherent to UWP, and therefore they may never be “fixed.” I’ll get to an example of this shortly.

Working Around UWP Limitations

A design decision I made early on is to limit the amount of UWP code in the Time Tortoise solution. There are good reasons for this that relate to unit testing and the MVVM pattern. However, this design decision also means that less code in the solution is directly tied to UWP. In the drastic scenario of migrating from UWP to WPF, much of the code could be directly ported. In less drastic scenarios (like the code coverage example), I can take advantage of all the functionality of .NET standard, without worrying about what UWP supports.

But as long as the core app is based on UWP, it is subject to some UWP limitations. In these cases, creative workarounds may be required to accomplish the goals of the app. By creative, I mean workarounds that don’t technically break any UWP rules, but nevertheless solve the problem in question.

An Example: Idle Time Detection

Here’s a feature I consider core to any usable time tracker: If I step away from my computer for more than a few minutes, I expect the time tracker to give me the option to exclude my “away time” when I return. Any time tracker that doesn’t offer this won’t provide accurate results. That’s because I won’t always remember to stop the timer when I leave the keyboard, I won’t always have a way to look up what the time was when I left, and even if I do know my departure time, I’d rather not have to fiddle with the time segment end time when I find myself in this situation.

A UWP app can keep track of user activity by monitoring CoreWindow events. However, those events only fire for user activity in the UWP app itself. But the user of a time tracker will normally be using several different apps, with the time tracker running in the background. So knowing only about their activity in the time tracker app isn’t very useful. We want to know whether or not they are active in any app on their computer. Unfortunately, listening to system-wide keyboard and mouse events isn’t likely to ever become a feature of UWP, since UWP apps are designed to be isolated from direct contact from other apps.

As indicated in this Stack Overflow answer and associated comments, there are Win32 API functions that allow monitoring system-wide user activity. But we can’t directly use them from UWP apps.

A Potential Solution

Since Time Tortoise is designed for Windows desktop users, I think the best approach to work around UWP limitations is to write an optional companion Win32 app that users can install to get additional functionality, like idle time detection. As I run into UWP limitations, I’ll be able to add functionality to the desktop app, which will communicate with the UWP app. In the idle time example, the companion app could track idle time and periodically provide this information to the UWP app, which could use it as appropriate (e.g., ask the user if they want to discard their away time). If a user chose not to install the companion app (or was using Time Tortoise on a device that didn’t support desktop apps), they would still be able to use Time Tortoise. They just wouldn’t get the extra functionality.

(Image credit: Jack Snell)