Creating a Watch

A few months ago I created a watch. Two actually. In a few hours. That is amazing and something which has only just become possible. This article is a tutorial and account of that process along with my take on the current smart watch/wear ecosystems. A lot of the documentation around this is unhelpful, relating to previous versions of Android Wear. I’ll point you to the useful stuff and include source code (but skip over that if you aren’t a developer). Creating a watch face on is a really interesting challenge, dealing with aesthetic concerns and with limitations and particularities of the hardware (OLED screens). You want to persistently display a time (in ‘ambient mode’), but using as few pixels as possible and not the same ones (prevent burn in). You want something elegant and informative but must worry about memory management in Java (well Kotlin, it is 2017!) and scheduling of rendering. But the constraints of a physical timepiece no longer apply; you get to build the future.

You can get the watch faces for free from Chronolight/Google Play. Given the number of downloads they are among the most exclusive watches in the world. Enjoy.

Background

As I was doing a major refresh of my productivity App Habit Streak I ended up back on Android after nearly 3 years on iOS. Having used an Apple Watch (more on that later) for 2 years I certainly wanted to continue with something equivalent. In the UK at the time (and I think still today) the obvious option (latest software and hardware features, battery life, availability) was the Huawei Watch 2. And Amazon had them on sale. Compared to a 38mm Apple Watch it is ridiculously large but does have an actual round and watch-like screen and the battery life was significantly better than an original Apple Watch. The big difference as a watch is that the screen stays on all the time, showing a low power watch face (which is updated every minute not at 60fps). Compared to Apple Watch, as a watch, there is no comparison: Android Wear actually is a usable watch; Apple Watch is a fitness device (and secondarily a remote control for your phone).

Of course as a developer there was another major attraction: I can build my own watch. Ridiculously this is still not possible on Apple Watch in any form. On Samsung’s (Tizen based) Gear Watch platform there is actually a piece of software that normal people can download and apparently create a fully customised watch (albeit by composing standard pieces like hands and digital displays). On Android there are Apps like Facer which allow you to create standard watch faces without programming. But to do something custom you will need Android Studio.

Getting Started: Guides and Learning Resources

I spent some time browsing and reading various pieces of documentation and tutorials. Unfortunately given how things have substantially changed many resources are quite out of date or otherwise confusing. Eventually I found the Google Code Lab on Android Wear Complications which contained a decent guide, but more importantly actual working source code. (There is another more basic codelab which might also be of interest.) There are in Java unfortunately but it was pretty easy to clean up the more unpleasant, verbose aspects with some judicious use of Kotlin.

Kotlin at 100%

The core idea

I started by quickly sketching the various way that time might reasonably be visualised. I definitely wanted something which gave an intuitive sense of time passing, but also retained the precision of digital. When it is is software you don’t have to choose. Bearing in mind the challenge around ambient mode I came up with the idea that the clock display itself could move through the day, its position forming a 24 hour clock orbiting the centre. I also wanted to include some complications (user selected additional pieces of information), which could orbit opposite. The final key element was a gradient background which would simulate sun rise and set. This would be hidden in ambient mode, yet fade in when you activate the watch.

Watch face ideas

Implementation

With this fairly clear idea I went about building it. The code from the Google code lab was helpful but creating a watch face is likely to necessitate very specific optimisations and trade offs. You really want to minimise the amount of work you are doing as far as possible, perhaps picking a small number of areas to push the boat out, while remaining very conservative elsewhere. For example I cared a lot about the transition between ambient mode and normal mode. I found watch faces which jumped from black, unlit OLED to bright colours to be jarring. On the positive side you get to write this in your build.grade:

minSdkVersion 25
targetSdkVersion 25

It will be many years before that min sdk will be at all reasonable for a regular Android App.

I made quite a lot of use of Kotlin, though given the context you have to try to avoid unnecessary object creation (in particular avoiding it in your main drawing code). If you are familiar with Android Canvas drawing you will find the basics pretty easy.

class Chronolight : CanvasWatchFaceService()

You are going to have to do some trigonometry, assuming you want to make use of the circular screen. But it is fairly simple and similar things will come up in most watch faces. For example here is some of the basic code (called on drawing each frame). Note how certain things have been created elsewhere (i.e. not each frame).

val now = System.currentTimeMillis()

calendar.timeInMillis = now
val milliSeconds = (now % 60000).toInt()

hours = calendar.get(Calendar.HOUR_OF_DAY)

val minutes = calendar.get(Calendar.MINUTE)
minutesOfDay = 60 * hours + minutes

val r = maxOf(bounds.width()/2, bounds.height()/2).toFloat()
angle = (hours - 6) * Math.PI / 12f
secondsAngle = (milliSeconds - 15000) * Math.PI / 30000f

With these basic quantities you can draw second hands (on in my case circles) and other such elements.

Kotlin allows the creation of extension functions on existing classes. This allows you to add in the methods missing from 3rd party libraries and keep you main business logic clean and clear. For example:

fun Canvas.drawCentredText(text: String, cx: Float, cy: Float, paint: Paint) {
    paint.getTextBounds(text, 0, text.length, workingTextBounds)
    drawText(text, cx - workingTextBounds.exactCenterX(), cy - workingTextBounds.exactCenterY(), paint)
}

It also has some nice tricks to make creating or building/configuring new objects really simple.

fun complicationDrawableWithContext(context: Context) : ComplicationDrawable {
    return ComplicationDrawable().apply {
        setContext(context)
        setBackgroundColorActive(Color.TRANSPARENT)
        setBorderColorActive(Color.TRANSPARENT)
        setIconColorActive(Color.LTGRAY)
    }
}

apply can take any object, evaluate a block of code in the context of that object then return the object. It is great for creating customised constructor logic.

The second version

I quite liked my first attempt at a watch, but it became clear a few things could be improved. Battery life was not amazing with it on (not terrible, but I’m guessing the use of gradient drawables, filling the background didn’t do the battery any favours). I also found the complications less interesting that I expected and wanted to preserve more of the pure dark background from ambient mode. I also wanted to take the idea a bit further. In addition to showing progress through the day, I wanted to display progress through the month and year.

By cutting out complications a lot of code disappeared. Indeed the final watch face was only around 200 lines of actual Kotlin. Ignoring the boilerplate it is just 100 lines or so (with some use of utility functions created for the other watch face). But to create an entire, original watch with such little effort is incredible.

Apple Watch, Today, The Future

I ended up back on iPhone a few months later. Unfortunately Apple doesn’t play nicely with others so the experience of using Android Wear there was frustrating and I ended up going back to Apple Watch which, even with its recent update to WatchOS 4, is still a terrible watch.

It will be interesting to see how things evolve over the next few years. It is fairly clear technical, hardware constraints are holding things back (particularly around battery life). But making it possible for anyone to create their own watch is pretty amazing. And hopefully Apple will catch up on this in some form soon.

See all posts