Android Wear / Data API / MobileCompanion / WatchFace

Something O’Clock – Part 6

On 1st April 2016 I published Something O’Clock, a watch face app for Android Wear, to Play Store. The app is lighthearted in nature (because of the date of publication), it allows the user to set the time to “beer o’clock”, or “sleep o’clock”, or even “burger o’clock”. Although the app itself is quite lighthearted the code behind it is worthy of study and, in this series we’ll take a look at various aspects of developing custom watch faces for Android Wear. In this concluding article we’ll look at how we update the watch-face UI in response to configuration changes.

round_wear_screenshotPreviously we have looked at how the mobile companion app enables the use to select different words from a list, this data then gets transmitted to the wear app using the Google Play Service DataApi framework. The wear app then persists this data locally, also using the DataApi with some built in data integrity protection. So now that we have the data stored locally, how do we trigger the UI update? The trick is to actually register our watch-face Engine component to listen for changes to the data we’re interested in. The first part of that process is to connect to the Play Services Wearable API:

In onCreate() we build the GoogleApiClient object but we don’t actually connect to it yet. The appropriate place to do this is onVisibilityChanged() because the lifecycle of a watch face is somewhat different to a standard service, so we start listening for data changes when we’re visible, but stop listening when we’re not.

When we build the GoogleApiClient we pass in a GoogleApiClient.ConnectionCallbacks instance which will receive callbacks once we’re connected:

Once we’re connected to Play Services, we create a LocalDataMap instance, we first fetch the local config and then look up the Uri for the local data, just as we did in the previous article. Once we have this Uri we register a data listener which will get called whenever the data is updated – similar to a ContentObserver. Hopefully the benefits of having this local data storage are now becoming apparent – we can have different components updating this data, but by marshalling it through this local storage we only need to register for updates from a single data source.

Both the fetchConfigDataMap() method and the onDataChanged() method of our DataListener use some common methods to decode the selected word from the data, and then update the UI:

When we update the UI, we change the time text in our textLayout and call invalidate() to force a redraw. The only thing remaining is to update TextLayout to add the appropriate method:

All of the code we looked at earlier in the series to size and position the text dynamically will now kick in and everything will be sized and positioned appropriately.

That’s it, when we select a new word from the list in the mobile companion app, then the watch face updates accordingly. Apologies that I am unable to include a video of this, but video capture from wear over adb wasn’t working for me – you’ll either have to just take my work for it, or try it yourself. Here are some static images of different words in action:




Although there is some scope for further enhancements such as having a companion app on the wear device itself, and allowing custom test strings to be used, we’ll leave it here for now as we’ve already gone in to quite a bit of depth. If anyone would be interested in me covering these, then please let me know and perhaps we’ll have a future series where we cover these enhancements.

So, for now, that concludes our dive in to the world of Android Wear custom watch-faces and companion apps.

The source code for this article is available here.

Many thanks to Daniele Bonaldo, Sebastiano Poggi, Erik Hellman, Hasan Hosgel, Said Tahsin Dane & Murat Yener – my beta testers.

Get it on Google Play

© 2016, Mark Allison. All rights reserved.

Copyright © 2016 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.