Posted by Garan Jenkin – Developer Relations Engineer
This submit is a part of Put on OS Highlight Week. As we speak, we’re specializing in creating partaking experiences throughout the varied surfaces accessible on the wrist.
Put your app’s distinctive data straight on a person’s watch face by constructing your individual problems. These are the small, glanceable particulars on a watch face, like step rely, date, or climate, which might be used to convey further data, 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, priceless data and hold customers linked to your app.
Let’s have a look at how one can construct your individual complication information sources, surfacing helpful data to the person straight on their watch face, and serving to drive engagement together with your app.

Key ideas of problems
With a purpose to assist perceive problems, let’s first assessment among the key architectural features of their design:
- Apps present solely a complication information supply – the watch face takes care of all structure 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?
Problems are nice for offering the person with bite-size information through the course of the day. Moreover, problems can present an excellent launch level into your full app expertise.
Problems Knowledge supply sorts (full record) embrace SHORT_TEXT and SMALL_IMAGE. Equally, watch faces declare what sorts they’ll render.
For instance, in the event you’re constructing an app which incorporates health targets, a sensible choice for a complication information supply may be one that gives the GOAL_PROGRESS or RANGED_VALUE information sorts, to point out progress towards that aim.
Conversely, problems are much less acceptable 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 aim 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 include // 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 non-obligatory information .setText(goalProgressText) .setTapAction(tapAction) .setMonochromaticImage(...) .construct() }
Observe: The GoalProgressComplicationData has quite a few non-obligatory fields along with the necessary ones. You must attempt to populate as many of those as you may.
Lastly, add the info supply to the manifest:
Observe: The usage of the directBootAware attribute on the service lets the complication service run earlier than the person has unlocked the gadget on boot.
Selecting your replace mannequin
Problems assist 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 properly for a situation similar to a climate complication, however in different eventualities, it could make extra sense for the updates to be pushed by the app. To realize 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 ought to be requested, for instance in a WorkManager job, or in WearableListenerService.
Leveraging platform bindings for high-frequency information
Notably for health-related problems, we will benefit from platform information sources, to enhance our aim 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 gap, it exhibits 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 method, the gap is up to date each second, without having for additional requests to the info supply. This implies UPDATE_PERIOD_SECONDS might 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 ought to be proven. Within the health aim instance, take into account that the person might need weekly, month-to-month, and yearly targets.
Including a configuration exercise permits them to pick which aim ought to 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:title=".MyGoalDataSourceService" ...> <meta-information android:title="android.assist.wearable.problems.PROVIDER_CONFIG_ACTION" android:worth="com.myapp.MY_GOAL_CONFIG" /> service> <exercise android:title=".MyGoalConfigurationActivity" ...> <intent-filter> <motion android:title="com.myapp.MY_GOAL_CONFIG" /> <class android:title="android.assist.wearable.problems.class.PROVIDER_CONFIG" /> <class android:title="android.intent.class.DEFAULT" /> intent-filter> exercise>
Within the exercise itself, the small print of the complication being configured might be extracted from the intent:
// Keys outlined on ComplicationDataSourceService // (-1 assigned when the ID or kind was not accessible) 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 end result when exiting:
setResult(Exercise.RESULT_OK) // Or RESULT_CANCELED to cancel configuration end()
The ID is identical ID handed in ComplicationRequest to the complication information supply service. The Exercise ought to write any configuration to an information 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 ought to be set as massive as is suitable for the use case: This reduces requests and improves battery life.
Take into account these examples:
- A identified record 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 must 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 record 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 might include 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 is no such thing as a occasion within the calendar defaultComplicationData = noEventComplicationData, // An inventory 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 the moment in use on the lively watch face or not. This will help with:
- Avoiding pointless work – for instance, if a climate complication has not been set within the lively watch face, then there is no such thing as a must allow a WorkManager job to periodically fetch climate updates, saving battery and community utilization.
- Aiding discovery – if onComplicationActivated has by no means been referred to 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 telephone 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) // Preserve observe of which complication has been enabled, and // begin any vital 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:
- Assist a number of sorts to maximise usefulness and compatibility – Watch faces will assist some complication information sorts, however doubtless not all of them.
- Use totally different information sources for various person journeys – Your app just isn’t restricted to offering one complication information supply. You must assist multiple you probably have totally different use circumstances to cater for. For instance, your well being and health app might need a complication to offer your progress in direction of your targets, but in addition a separate complication to point out sleep stats.
- Keep away from heavy work in onComplicationRequest() – For instance,if the progress towards a health aim 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 elements – When in use, your information supply service can be began when the Put on OS gadget begins up, and at different instances through the day. You must keep away from the service needing too many different elements from inside your app to be began to be able to run, to take care of good system efficiency.
- Take into account backup and restore – If the complication is configurable, it’d make sense to revive these settings – study implement backup and restore for complication information sources.
- Take into consideration the invention journey – Your problems can be accessible as an choice on the person’s watch face when your app is put in on the watch. Take into account how one can promote and educate the person on this performance, each in your telephone app and your Put on OS app, and leverage strategies similar to onComplicationActivated() to tell this course of.
Including assist to your information supply for a number of sorts makes it most helpful to the person. Within the above instance, we carried out each RANGED_VALUE and GOAL_PROGRESS, as each can be utilized to characterize progress-type information.
Equally, in the event you have been to implement a calendar complication, you possibly can use each SHORT_TEXT and LONG_TEXT to maximise compatibility with the accessible slots on the watch face.
Assets for creating problems
Problems are a good way to raise your app expertise for customers, and to distinguish your app from others.
Take a look at these sources for extra data on creating complication information sources. We look ahead to seeing what you are able to do.
Pleased Coding!