The most popular mobile operating system is known to be Android. One of the main reasons for its popularity is its ability to run on a huge number of devices, not only on phones and tablets. We find Android on TVs, watches, cars, even fridges and mirrors.
Android Wear is the version of the operating system specifically designed to extend the Android platform to wearables, with particular attention to smartwatches. These devices allow the user to consume information in a completely different way than traditional handheld devices: Data is presented at the right time depending on the user’s context, and interaction is less invasive and time-consuming than in a phone app.
Further Reading on SmashingMag:
- Getting Started With Wearables: How To Plan, Build And Design
- Designing For Smartwatches And Wearables
- Intimate And Interruptive: Designing For The Power Of Apple Watch
- The Wireframe Perfectionist’s Guide
This article shows how to make your app’s data available directly from a wearable watch face, allowing the user to access it at a glance. We’ll see how to sync data between a phone and smartwatch and how to display it using the new Complications API.
Watch Faces And Complications
What are these complications, to start with? In the context of traditional watchmaking, a complication is, as defined by Wikipedia:
”…any feature in a timepiece beyond the simple display of hours and minutes.”
Some of the best-known examples of complications are the date display, a chronometer or a second time indicator.
Complications are certainly nothing new in mechanical watches. We have the first reports of pocket watches including extra complications from back in the 16th century.
Smartwatches are the perfect house for these kinds of additional features, thanks to the huge potential provided by digital screens.
The most popular type of app for smartwatches today is the watch face, and for a good reason: It is displayed for most of the time on the watch’s display, when no other app is in use. Thousands of watch faces are available in the Play store, each with a different style.
One of the main principles of Android Wear is glanceability: The user should always be able to consume the displayed information in a split second, without any interruption to their activity. Complications are created exactly with this principle in mind: While the main purpose of a watch face is to enable the user to tell the time, complications can be even more useful, displaying an array of information without requiring the user to open a different app.
In Android Wear, we already have several examples of watch faces that include complications. They display information such as a step counter, the weather forecast, details about the user’s next meeting and much more.
The way these complications have worked so far had a big limitation: Every single watch face app had to implement its own logic to fetch the data. If two watch faces displayed the weather forecast, for example, the developers had to implement two similar mechanisms to fetch the same data. Such a waste of resources!
Android Wear 2.0 aims to solve this problem with the new Complications API.
Wear’s Complications API
Specifically, Android Wear puts two main actors into communication:
- the data provider, which includes the logic to fetch the data;
- the watch face, which displays the information exposed by the data provider.
A watch face never has direct access to a data provider. It will instead receive a callback when new data is available for the complications that the user has selected. Meanwhile, the data provider doesn’t know how the exposed information will be displayed: That is completely up to the watch face, depending on its style.
Complication Types
To define some sort of communication protocol between the two actors, the Complications API specifies a set of complication types that can be used by a provider when exposing data.
Each type has at least one required field, which is the primary piece of data. The watch face always expects to receive this field, and some optional fields can be used to provide additional information.
In the “Short Text” type, for example, the required field is a short amount of text, which may be accompanied by a short title or an icon to make the main information even more explicit. Icons in general should be a single color with transparency, because they might be tinted by the watch face.
The following table summarizes the required and optional fields for every complication type:
Complication type | Required fields | Optional fields |
---|---|---|
Short Text | Short text | Icon Short title |
Icon | Icon | |
Ranged Value | Value Minimum value Maximum value | Icon Short text Short title |
Long Text | Long text | Long title Icon Small image |
Small Image | Small image | |
Large Image | Large image |
Use Case
It became immediately apparent to me that this new API has huge potential. So, I decided to use it with an existing project, in order to expose some already available data from the app using an ad-hoc complication.
The project is an open-source app created by my friend Alexandros, which I’ve been using for a while now: Memento Namedays. The purpose of the app is to remind you of birthdays and name days of your contacts, and this looks like a perfect use case for a complication to display information about the next birthday among your contacts.
Let’s have a look at how I managed to create the data provider.
Syncing Data Between Handheld and Wearable
The code for the phone app was included in an Android module named mobile
. I created another module named wear
, which includes the code for the part of the app to be installed on the smartwatch. I then made the required data from mobile
available to the wear
module of the app.
The phone app already has a service for checking every day for upcoming birthdays and name days, and that became the perfect access point to fetch the data needed by the complication.
Every time a relevant change happens (for example, when the birthday of one of my contacts arrived), I used the Wearable Data Layer API to sync this data between the handheld and wearable.
Exposing the Complication Data
In the wear
module, I created the complication data provider, which is a service that extends ComplicationProviderService
. This base class gives us a set of callbacks for us to know the status of our complication:
onComplicationActivated
tells us when the provider is selected as the data source for a complication in the current watch face.onComplicationDeactivated
tells us when the complication is not selected anymore.onComplicationUpdate
tells us when it is time to provide an updated set of data to populate the complication.
The last method is the most important one, because there we need to load new data and bundle it to be forwarded to the watch face.
Among the callback parameters, the complication type allows the data provider to add the required fields according to the type supported by the watch face.
In the case of a “Short Text” type, I populate ComplicationData
with the date of the next event and an optional icon:
ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
.setShortText(ComplicationText.plainText(formatShortDate(date)))
.setIcon(Icon.createWithResource(context, R.drawable.ic_event))
.setTapAction(createContactEventsActivityIntent())
.build();
In the case of a “Long Text,” I add the list of contact names associated with the next event:
ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
.setLongTitle(ComplicationText.plainText(formatLongDate(date)))
.setLongText(ComplicationText.plainText(formatList(names)))
.setIcon(Icon.createWithResource(context, R.drawable.ic_event))
.setTapAction(createContactEventsActivityIntent())
.build();
Note that complications may be made tappable by the user directly from the watch face. To support this, I used the builder method setTapAction
to specify a PendingIntent
, pointing to an activity displaying all information for the given event. It is then responsibility of the watch face to trigger that PendingIntent
on the user’s tap.
In the following picture, we see the final result. From left to right, the exposed complication with the “Short Text” and “Long Text” types are displayed on two different watch faces, and the activity displays the event details.
Updating the Data
It is possible to specify an update period for the ComplicationProviderService
in its manifest entry using the following key:
android.support.wearable.complications.UPDATE_PERIOD_SECONDS
This value should be set as high as possible, in order to minimize the impact on the device’s battery from frequent updates. Also, note that this value does not guarantee a constant update frequency: The system will optimize the update calls depending on the status of the device (setting less frequent updates if the device is in ambient mode or is not being worn).
In our case, the complication data doesn’t change often, and the phone app already handles that logic of updating the synced data. I decided, then, to be a good citizen and go for a push-style update mechanism.
First, I disabled automatic data refreshing by setting the UPDATE_PERIOD_SECONDS
value to 0
in the manifest.
I then used a WearableListenerService
to receive a callback every time some updated data is synced for a given URI. In this case, it’s the one I used to sync data between mobile
and wear
. When this happens, I manually request an update using a ProviderUpdateRequester
:
public class DataChangedListenerService extends WearableListenerService {
@Override
public void onDataChanged(DataEventBuffer dataEventBuffer) {
super.onDataChanged(dataEventBuffer);
ComponentName providerComponentName = new ComponentName(
context,
MyComplicationProviderService.class
);
ProviderUpdateRequester providerUpdateRequester = new
ProviderUpdateRequester(context, providerComponentName);
providerUpdateRequester.requestUpdateAll();
}
}
All of the code for this article is available on GitHub.
You will see how easy it is to update an existing app to sync data between a phone and smartwatch, and then to display it on a watch face using the new Complications API.
Conclusion
Thanks to the Complications API, every Android application can easily export the most important data and make it accessible at a glance directly on the user’s wrist, even without requiring a dedicated watch face.
At the time of writing, this API is still in a preview state, so it might change before the final release of Android Wear 2.0, but its potential is already very interesting.
If a lot of apps are updated to use this new API, we will have a prosperous ecosystem of complications for users to choose from, with information-rich watch faces and a great increase in usefulness in our connected devices!
For more information on the Complications API, please have a look at the official documentation.