Data provider apps expose information to watch face complications, supplying fields that contain text, strings, images, and numbers.
A data provider service extends
ComplicationProviderService
to deliver useful
information directly to a watch face.
Refer to the following related resources:
Create a data provider project
To create a project in Android Studio for your data provider app:
- Click File > New > New project.
- In the Create Android Project window, accept the default values and click Next.
- In the Target Android Devices window, select only the Wear option, and in the list of SDK versions, select the latest available version. Click Next.
- In the Add an Activity to Wear window, select
Add No Activity and click Finish.
Android Studio creates a project with an
app
module for your data provider. For more information about projects in Android Studio, see Create a Project. - Begin your data provider app by creating a new class that extends
BroadcastReceiver
. The purpose of that class is to listen for complication update requests from the Wear OS system. Additionally, create a new class that extendsComplicationProviderService
in order to actually provide data as requested by appropriate complications. For more information, see the following:- Implementing a method for update requests
- The
ComplicationTapBroadcastReceiver
andCustomComplicationProviderService
classes in the following codelab: Exposing your Data to Complications ComplicationToggleReceiver
,LongTextProviderService
, and other classes in the test suite sample
Note: Adding an activity for your data provider is optional. You may want to add an activity that launches only when a user taps a complication, for example.
Implementing a method for update requests
When complication data is needed, the Wear OS system sends update requests to your data
provider. The requests are received by your
BroadcastReceiver
. To respond to the update requests,
your data provider must implement the
onComplicationUpdate()
method of the ComplicationProviderService
class. The Wear OS system calls this method when data is needed from your provider, e.g.,
when a complication using your provider becomes active, or when a fixed amount of time has
passed.
A
ComplicationManager
object is passed as a parameter to the
onComplicationUpdate
method, and can be used to send data back to the system.
Note: When your data provider app provides data, the watch face receives the raw values that you send, so the watch face can draw the information.
The following code snippet shows a sample implementation of the
onComplicationUpdate
method:
Kotlin
override fun onComplicationUpdate( complicationId: Int, dataType: Int, complicationManager: ComplicationManager) { Log.d(TAG, "onComplicationUpdate() id: $complicationId") // Used to create a unique key to use with SharedPreferences for this complication. val thisProvider = ComponentName(this, javaClass) // Retrieves your data, in this case, we grab an incrementing number from SharedPrefs. val preferences = getSharedPreferences(ComplicationTapBroadcastReceiver.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0) val number = preferences.getInt( ComplicationTapBroadcastReceiver.getPreferenceKey( thisProvider, complicationId), 0) val numberText = String.format(Locale.getDefault(), "%d!", number) var complicationData: ComplicationData? = null when (dataType) { ComplicationData.TYPE_SHORT_TEXT -> complicationData = ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT) .setShortText(ComplicationText.plainText(numberText)) .build() else -> if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Unexpected complication type $dataType") } } if (complicationData != null) { complicationManager.updateComplicationData(complicationId, complicationData) } else { // If no data is sent, we still need to inform the ComplicationManager, so // the update job can finish and the wake lock isn't held any longer. complicationManager.noUpdateRequired(complicationId) } }
Java
@Override public void onComplicationUpdate( int complicationId, int dataType, ComplicationManager complicationManager) { Log.d(TAG, "onComplicationUpdate() id: " + complicationId); // Used to create a unique key to use with SharedPreferences for this complication. ComponentName thisProvider = new ComponentName(this, getClass()); // Retrieves your data, in this case, we grab an incrementing number from SharedPrefs. SharedPreferences preferences = getSharedPreferences( ComplicationTapBroadcastReceiver.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0); int number = preferences.getInt( ComplicationTapBroadcastReceiver.getPreferenceKey( thisProvider, complicationId), 0); String numberText = String.format(Locale.getDefault(), "%d!", number); ComplicationData complicationData = null; switch (dataType) { case ComplicationData.TYPE_SHORT_TEXT: complicationData = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT) .setShortText(ComplicationText.plainText(numberText)) .build(); break; default: if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Unexpected complication type " + dataType); } } if (complicationData != null) { complicationManager.updateComplicationData(complicationId, complicationData); } else { // If no data is sent, we still need to inform the ComplicationManager, so // the update job can finish and the wake lock isn't held any longer. complicationManager.noUpdateRequired(complicationId); } }
Manifest declarations and permissions
Data provider apps must include specific declarations in their app manifest to be treated as
a data provider by the Android system. This section explains the required settings for
data provider apps.
In your app's manifest, declare the service and add an update request action intent filter.
The manifest must also protect the service by adding the BIND_COMPLICATION_PROVIDER
permission to ensure that only the Wear OS system can bind to provider services.
In addition, within the service element, you must include an
android:icon
attribute. The provided icon should be a
single-color white icon. Vector drawables are recommended for the icons.
An icon should represent the provider and will be shown in the provider
chooser.
Here's an example:
<service android:name=".provider.IncrementingNumberComplicationProviderService" android:icon="@drawable/icn_complications" android:label="@string/complications_provider_incrementing_number" android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER"> <intent-filter> <action android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/> </intent-filter> </service>
Specify the meta data elements
In your manifest file, include metadata to specify the supported types, update period, and configuration action, as shown in the following example:
<meta-data android:name="android.support.wearable.complications.SUPPORTED_TYPES" android:value="RANGED_VALUE,SHORT_TEXT,LONG_TEXT" /> <meta-data android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS" android:value="300" />
When your complication data provider is active,
UPDATE_PERIOD_SECONDS
specifies how often you want the
system to check for updates to the data. If the information shown in the
complication doesn't need to update on a regular schedule, such as when
you're using push updates, set this value to
0
.
If you don't set UPDATE_PERIOD_SECONDS
to 0
,
you must use a value of at least 300
(5 minutes), which is
the minimum update period that the system enforces in order to preserve
device battery life. In addition, keep in mind that update requests may
come less often when the device is in ambient mode or isn't being worn.
For more details on sending updates, see the keys listed for the
ComplicationProviderService
class in the
Wear API
Reference.
Add a configuration activity
If required, a provider can include a configuration activity that is shown to the user when the user chooses a data provider. To include the configuration activity, include a metadata item in the provider service declaration in the manifest with a key of the following:
<meta-data android:name="android.support.wearable.complications.PROVIDER_CONFIG_ACTION" android:value="PROVIDER_CONFIG_ACTION"/>
The value can be an action of your choice.
Then create the configuration activity with an intent filter for that
action. The configuration activity must reside in the same package as the
provider. The configuration activity must return RESULT_OK
or
RESULT_CANCELED
, to tell the system whether the provider
should be set.
Provider-specified safe watch faces
Providers can specify certain watch faces as "safe" to receive their data. This is intended to be used only when a watch face will attempt to use the provider as a default (see below), and the provider trusts the watch face app.
To declare watch faces as safe, the provider adds metadata with a key of
android.support.wearable.complications.SAFE_WATCH_FACES
. The
metadata value should be a comma-separated list (whitespace is ignored).
Entries in the list can be component names (of
WatchFaceServices
, given as if
ComponentName.flattenToString()
had been called), or they
can be package names (of apps, in which case every watch face within a
specified app is considered safe). For example:
<meta-data android:name="android.support.wearable.complications.SAFE_WATCH_FACES" android:value=" com.app.watchface/com.app.watchface.MyWatchFaceService, com.anotherapp.anotherwatchface/com.something.WatchFaceService, com.something.text"/>
Provide burn-in safe images
On screens susceptible to burn-in, solid blocks of color should be avoided in ambient mode. If your icons or images include solid blocks of color, you should also provide a burn-in safe version.
When you provide an icon using
ComplicationData.Builder#setIcon
, include a burn-in safe version
using
ComplicationData.Builder#setBurnInProtectionIcon
.
When you provide an image using
ComplicationData.Builder#setSmallImage
, include a burn-in safe version
using
ComplicationData.Builder#setBurnInProtectionSmallImage
.
Use push updates
As an alternative to specifying a constant, nonzero update interval for a
complication in your app's manifest, you can use an instance of
ProviderUpdateRequester
to request updates dynamically.
To request an update to the complication's user-visible content, call
onComplicationUpdate()
.
Caution: To preserve device battery life, your
instance of ProviderUpdateRequester
shouldn't call
onComplicationUpdate()
more often than every 5 minutes on
average.
Provide time-dependent values
Some complications need to display a value that relates to the current time. Examples include the current date, the time until the next meeting, or the time in another time zone.
Do not update a complication every
second or minute to keep those values up to date; a complication should never need to update
that often. Instead, specify
the values as relative to the current date or time using time-dependent text.
You can use builders in the
ComplicationText
class to create these time-dependent values.