Menu Search
Jump to the content X X
Smashing Conf New York

You know, we use ad-blockers as well. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. our upcoming SmashingConf New York, dedicated to smart front-end techniques and design patterns.

Bringing Your App’s Data To Every User’s Wrist With Android Wear

The most popular mobile operating system is known to be Android1. 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 mirrors2.

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: Link

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 Link

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.

A mechanical watch movement7
The movement of the first mechanical watch that I built (View large version8)

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 Link

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.
The Complication API flow9
The Complication API’s flow (View large version10)

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 Link

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.

Different complication types11
Complication types (Image: d.android.com12) (View large version13)

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 Link

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 Alexandros14, which I’ve been using for a while now: Memento Namedays15. 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 Link

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 API16 to sync this data between the handheld and wearable.

Exposing the Complication Data Link

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.

Screenshots of the complications created17
The result: “Short Text” and “Long Text” complications and the activity launched upon a tap (View large version18)

Updating the Data Link

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 GitHub19.

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 Link

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 documentation20.

(da, yk, al, il)

Footnotes Link

  1. 1 https://www.netmarketshare.com/operating-system-market-share.aspx?qprid=8&qpcustomd=1
  2. 2 https://medium.com/@danybony_/mirror-smart-mirror-on-the-wall-a211a73456f5
  3. 3 https://www.smashingmagazine.com/2015/10/getting-started-wearables-plan-build-design/
  4. 4 https://www.smashingmagazine.com/2015/02/designing-for-smartwatches-wearables/
  5. 5 https://www.smashingmagazine.com/2015/10/intimate-interruptive-designing-power-apple-watch/
  6. 6 https://www.smashingmagazine.com/2016/11/wireframe-perfectionist-guide/
  7. 7 https://www.smashingmagazine.com/wp-content/uploads/2016/11/movement-large-preview-opt.jpg
  8. 8 https://www.smashingmagazine.com/wp-content/uploads/2016/11/movement-large-preview-opt.jpg
  9. 9 https://www.smashingmagazine.com/wp-content/uploads/2016/11/complications_flow-large-preview-opt.png
  10. 10 https://www.smashingmagazine.com/wp-content/uploads/2016/11/complications_flow-large-preview-opt.png
  11. 11 https://www.smashingmagazine.com/wp-content/uploads/2016/11/complications_types-large-preview-opt.png
  12. 12 http://d.android.com
  13. 13 https://www.smashingmagazine.com/wp-content/uploads/2016/11/complications_types-large-preview-opt.png
  14. 14 https://twitter.com/alexstyl
  15. 15 https://github.com/alexstyl/Memento-Namedays
  16. 16 https://developer.android.com/training/wearables/data-layer/index.html
  17. 17 https://www.smashingmagazine.com/wp-content/uploads/2016/11/screenshots-large-preview-opt.png
  18. 18 https://www.smashingmagazine.com/wp-content/uploads/2016/11/screenshots-large-preview-opt.png
  19. 19 https://github.com/alexstyl/Memento-Namedays/pull/40
  20. 20 https://developer.android.com/wear/preview/features/complications.html

↑ Back to top Tweet itShare on Facebook

Daniele Bonaldo is an Android developer at Novoda and Google Developer Expert for Wearables. He’s passionate about photography and wearable technologies. Before working at Novoda, he worked at i’m Spa, an Italian startup where he had the chance to play with the Android platform while developing one of the first smartwatches on the market ("Doing smartwatchases before it was cool" as they said).

Now he loves to work on everything related to the Android ecosystem, from Chromecast to Wear to smart mirrors.

  1. 00

    No comments have been posted yet. Please feel free to comment first!
    Note: Make sure your comment is related to the topic of the article above. Let's start a personal and meaningful conversation!

Leave a Comment

You may use simple HTML to add links or lists to your comment. Also, use <pre><code class="language-*">...</code></pre> to mark up code snippets. We support -js, -markup and -css for comments.

↑ Back to top