
Posted by Garan Jenkin – Developer Relations Engineer
This publish is a part of Put on OS Highlight Week. Right this moment, we’re specializing in creating partaking experiences throughout the assorted surfaces out there on the wrist.
Put your app’s distinctive info immediately on a person’s watch face by constructing your personal problems. These are the small, glanceable particulars on a watch face, like step depend, date, or climate, which can be used to convey further info, past merely telling the time.
Watches such because the recently-launched Pixel Watch 4 function watch faces with as many as 8 problems. These small, highly effective show parts are a good way to offer fast, invaluable info and hold customers linked to your app.
Let’s have a look at how one can construct your personal complication information sources, surfacing helpful info to the person immediately on their watch face, and serving to drive engagement together with your app.

Key rules of problems
As a way to assist perceive problems, let’s first evaluate among the key architectural elements of their design:
- Apps present solely a complication information supply – the watch face takes care of all format and rendering.
- Complication information is typed – each complication information sources and watch faces specify which sorts are supported respectively.
- Watch faces outline slots – these are areas on the watch face that may host problems.

What are problems good for?
Issues are nice for offering the person with bite-size information through the course of the day. Moreover, problems can present a fantastic launch level into your full app expertise.
Issues Information supply sorts (full listing) embrace SHORT_TEXT and SMALL_IMAGE. Equally, watch faces declare what sorts they will render.
For instance, should you’re constructing an app which incorporates health objectives, a good selection for a complication information supply is likely to be one that gives the GOAL_PROGRESS or RANGED_VALUE information sorts, to indicate progress towards that objective.
Conversely, problems are much less applicable for bigger quantities of information, such because the contents of a chat message. They’re additionally not appropriate for very frequent updates, similar to real-time health metrics generated by your app.
Making a complication information supply
Let’s have a look at making a complication information supply for that health objective talked about above.
First, we create a service that extends SuspendingComplicationDataSourceService:
class MyDataSourceService : SuspendingComplicationDataSourceService() { override droop enjoyable onComplicationRequest(request: ComplicationRequest): ComplicationData? { // Deal with each GOAL_PROGRESS and RANGED_VALUE return when (request.complicationType) { ComplicationType.GOAL_PROGRESS -> goalProgressComplicationData() ComplicationType.RANGED_VALUE -> rangedValueComplicationData() else -> NoDataComplicationData() } } // Apps ought to override this in order that watch face previews comprise // complication information override enjoyable getPreviewData(kind: ComplicationType) = createPreviewData() }
To create the precise information to return, we create a ComplicationData object, proven right here for GOAL_PROGRESS:
enjoyable goalProgressComplicationData(): ComplicationData { val goalProgressText = PlainComplicationText .Builder("${goalProgressValue.toInt()} km") .construct() return GoalProgressComplicationData.Builder( worth = goalProgressValue, targetValue = goalTarget, contentDescription = goalProgressText ) // Set some further optionally available information .setText(goalProgressText) .setTapAction(tapAction) .setMonochromaticImage(...) .construct() }
Word: The GoalProgressComplicationData has quite a few optionally available fields along with the necessary ones. It’s best to attempt to populate as many of those as you may.
Lastly, add the info supply to the manifest:
<service android:identify=".WorkoutStatusDataSourceService" android:exported="true" android:directBootAware="true" android:label="@string/status_complication_label" android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER"> <intent-filter> <motion android:identify="android.help.wearable.problems.ACTION_COMPLICATION_UPDATE_REQUEST" /> </intent-filter> <!-- Supported information sorts. Word that the choice order of the watch face, not the complication information supply, decides which sort will probably be chosen. --> <meta-data android:identify="android.help.wearable.problems.SUPPORTED_TYPES" android:worth="GOAL_PROGRESS,RANGED_VALUE" /> <meta-data android:identify="android.help.wearable.problems.UPDATE_PERIOD_SECONDS" android:worth="300" /> </service>
Word: Using the directBootAware attribute on the service lets the complication service run earlier than the person has unlocked the machine on boot.
Selecting your replace mannequin
Issues help each a push and a pull-style replace mechanism. Within the instance above, UPDATE_PERIOD_SECONDS is ready such that the info is refreshed each 5 minutes. Put on OS will examine the up to date worth of the complication information supply with that frequency.
This works nicely for a situation similar to a climate complication, however in different situations, it might make extra sense for the updates to be pushed by the app. To attain this, you may:
- Set UPDATE_PERIOD_SECONDS to 0 to point that the app will drive the replace course of.
- Utilizing ComplicationDataSourceUpdateRequester in your app code to sign to the Put on OS system that an replace must be requested, for instance in a WorkManager job, or in WearableListenerService.
Leveraging platform bindings for high-frequency information
Significantly for health-related problems, we will benefit from platform information sources, to enhance our objective progress complication. We will use these information sources with dynamic expressions to create complication content material which is dynamically re-evaluated each second whereas the watch face is in interactive mode (that’s, when it’s not in system ambient / always-on mode).
Let’s replace the complication in order that as a substitute of simply displaying the space, it reveals a celebratory message when the goal is reached. First we create a dynamic string as follows:
val distanceKm = PlatformHealthSources.dailyDistanceMeters().div(1000f) val formatter = DynamicBuilders.DynamicFloat.FloatFormatter.Builder() .setMaxFractionDigits(2) .setMinFractionDigits(0) .construct() val goalProgressText = DynamicBuilders.DynamicString .onCondition(distanceKm.lt(distanceKmTarget)) .use( distanceKm .format(formatter) .concat(DynamicBuilders.DynamicString.fixed(" km")) ) .elseUse( DynamicBuilders.DynamicString.fixed("Success!") )
Then we embrace this textual content, and the dynamic worth distanceKm, with the dynamic model of the complication builder.
On this means, the space is up to date each second, without having for additional requests to the info supply. This implies UPDATE_PERIOD_SECONDS may be set to a big worth, saving battery, and the celebratory textual content is straight away proven the second they go their goal!
Configuring problems
For some information sources, it’s helpful to let the person configure what information must be proven. Within the health objective instance, take into account that the person might need weekly, month-to-month, and yearly objectives.
Including a configuration exercise permits them to pick which objective must be proven by the complication. To do that, add the PROVIDER_CONFIG_ACTION metadata to your service definition, and implement an exercise with a filter for this intent, for instance:
<service android:identify=".MyGoalDataSourceService" ...> <!-- ... --> <meta-information android:identify="android.help.wearable.problems.PROVIDER_CONFIG_ACTION" android:worth="com.myapp.MY_GOAL_CONFIG" /> </service> <exercise android:identify=".MyGoalConfigurationActivity" ...> <intent-filter> <motion android:identify="com.myapp.MY_GOAL_CONFIG" /> <class android:identify="android.help.wearable.problems.class.PROVIDER_CONFIG" /> <class android:identify="android.intent.class.DEFAULT" /> </intent-filter> </exercise>
Within the exercise itself, the small print of the complication being configured may be extracted from the intent:
// Keys outlined on ComplicationDataSourceService // (-1 assigned when the ID or kind was not out there) val id = intent.getIntExtra(EXTRA_CONFIG_COMPLICATION_ID, -1) val kind = intent.getIntExtra(EXTRA_CONFIG_COMPLICATION_TYPE, -1) val supply = intent.getStringExtra(EXTRA_CONFIG_DATA_SOURCE_COMPONENT)
To point a profitable configuration, the exercise ought to set the consequence when exiting:
setResult(Exercise.RESULT_OK) // Or RESULT_CANCELED to cancel configuration end()
The ID is similar ID handed in ComplicationRequest to the complication information supply service. The Exercise ought to write any configuration to a knowledge retailer, utilizing the ID as a key, and the service can retrieve the suitable configuration to find out what information to return in response to every onComplicationRequest().
Working effectively with time and occasions
Within the instance above, UPDATE_PERIOD_SECONDS is ready at 5 minutes – that is the smallest worth that may be set for the replace interval. Ideally this worth must be set as giant as is appropriate for the use case: This reduces requests and improves battery life.
Think about these examples:
- A identified listing of occasions – For instance a calendar. On this case, use SuspendingTimelineComplicationDataSourceService.
This lets you present the sequence of occasions prematurely, without having for the watch face to request updates. The calendar information supply would solely have to push updates if a change is made, similar to one other occasion being scheduled for the day, providing timeliness and effectivity.
ComplicationDataTimeline requires a defaultComplicationData in addition to the listing of entries: That is used within the case the place not one of the timeline entries are legitimate for the present time. For instance, for a calendar it may comprise the textual content “No occasion” the place the person has nothing booked. The place there are overlapping entries, the entry with the shortest interval is chosen.
override droop enjoyable onComplicationRequest(request: ComplicationRequest): ComplicationDataTimeline? { return ComplicationDataTimeline( // The default for when there isn't a occasion within the calendar defaultComplicationData = noEventComplicationData, // A listing of calendar entries timelineEntries = listOf( TimelineEntry( validity = TimeInterval(event1.begin, event1.finish), complicationData = event1.complicationData ), TimelineEntry( validity = TimeInterval(event2.begin, event2.finish), complicationData = event2.complicationData ) ) ) }
TimeDifferenceComplicationText.Builder( TimeDifferenceStyle.SHORT_SINGLE_UNIT, CountDownTimeReference(newYearInstant) ) .setDisplayAsNow(true) .construct()
Working with activation and deactivation
It may be very helpful to trace whether or not your complication is at present in use on the energetic watch face or not. This can assist with:
- Avoiding pointless work – for instance, if a climate complication has not been set within the energetic watch face, then there isn’t a have to allow a WorkManager job to periodically fetch climate updates, saving battery and community utilization.
- Aiding discovery – if onComplicationActivated has by no means been known as, then the person has by no means used your complication on a watch face.
This could be a helpful sign to offer an academic second in your cellphone or Put on OS app, drawing consideration to this function, and sharing potential advantages with the person that they will not be conscious of.
To facilitate these use circumstances, override the suitable strategies in your complication service:
class MyDataSourceService() : SuspendingComplicationDataSourceService() { override enjoyable onComplicationActivated(complicationInstanceId: Int, kind: ComplicationType) { tremendous.onComplicationActivated(complicationInstanceId, kind) // Hold observe of which complication has been enabled, and // begin any essential work similar to registering periodic // WorkManager jobs } override enjoyable onComplicationDeactivated(complicationInstanceId: Int) { tremendous.onComplicationDeactivated(complicationInstanceId) // Complication occasion has been disabled, so take away all // registered work }
Some further factors to contemplate when implementing your information sources:
- Help a number of sorts to maximise usefulness and compatibility – Watch faces will help some complication information sorts, however seemingly not all of them.
- Use completely different information sources for various person journeys – Your app shouldn’t be restricted to offering one complication information supply. It’s best to help multiple you probably have completely different use circumstances to cater for. For instance, your well being and health app might need a complication to offer your progress in the direction of your objectives, but additionally a separate complication to indicate sleep stats.
- Keep away from heavy work in onComplicationRequest() – For instance,if the progress towards a health objective entails intensive processing of a lot of exercises, do that elsewhere. The request to the complication information supply ought to ideally simply return the worth with minimal computation.
- Keep away from your service having in depth dependencies on different app parts – When in use, your information supply service will probably be began when the Put on OS machine begins up, and at different instances through the day. It’s best to keep away from the service needing too many different parts from inside your app to be began in an effort to run, to keep up good system efficiency.
- Think about backup and restore – If the complication is configurable, it’d make sense to revive these settings – be taught the way to implement backup and restore for complication information sources.
- Take into consideration the invention journey – Your problems will probably be out there as an possibility on the person’s watch face when your app is put in on the watch. Think about how one can promote and educate the person on this performance, each in your cellphone app and your Put on OS app, and leverage strategies similar to onComplicationActivated() to tell this course of.
Including help to your information supply for a number of sorts makes it most helpful to the person. Within the above instance, we applied each RANGED_VALUE and GOAL_PROGRESS, as each can be utilized to symbolize progress-type information.
Equally, should you had been to implement a calendar complication, you might use each SHORT_TEXT and LONG_TEXT to maximise compatibility with the out there slots on the watch face.
Assets for creating problems
Issues are a good way to raise your app expertise for customers, and to distinguish your app from others.
Take a look at these assets for extra info on creating complication information sources. We stay up for seeing what you are able to do.
Completely happy Coding!
