Google is committed to advancing racial equity for Black communities. See how.

WatchFaceService

abstract class WatchFaceService : WallpaperService
kotlin.Any
   ↳ android.content.Context
   ↳ android.content.ContextWrapper
   ↳ android.app.Service
   ↳ android.service.wallpaper.WallpaperService
   ↳ androidx.wear.watchface.WatchFaceService

WatchFaceService and WatchFace are a pair of base classes intended to handle much of the boilerplate needed to implement a watch face without being too opinionated. The suggested structure of an WatchFaceService based watch face is:

import android.graphics.RectF
import androidx.wear.complications.DefaultComplicationProviderPolicy
import androidx.wear.watchface.complications.rendering.ComplicationDrawable
import androidx.wear.watchface.CanvasComplicationDrawable
import androidx.wear.watchface.ComplicationsManager
import androidx.wear.watchface.style.ListUserStyleSetting
import androidx.wear.watchface.style.UserStyleRepository
import androidx.wear.watchface.style.UserStyleSchema

class ExampleCanvasWatchFaceService : WatchFaceService() {
    override fun createWatchFace(
        surfaceHolder: SurfaceHolder,
        watchFaceHost: WatchFaceHost,
        watchState: WatchState
    ): WatchFace {
        val userStyleRepository = UserStyleRepository(
            UserStyleSchema(
                listOf(
                    ListUserStyleSetting(
                        "color_style_setting",
                        "Colors",
                        "Watchface colorization",
                        icon = null,
                        options = listOf(
                            ListUserStyleSetting.ListOption(
                                "red_style",
                                "Red",
                                icon = null
                            ),
                            ListUserStyleSetting.ListOption(
                                "green_style",
                                "Green",
                                icon = null
                            ),
                            ListUserStyleSetting.ListOption(
                                "bluestyle",
                                "Blue",
                                icon = null
                            )
                        ),
                        listOf(Layer.BASE_LAYER, Layer.COMPLICATIONS, Layer.TOP_LAYER)
                    ),
                    ListUserStyleSetting(
                        "hand_style_setting",
                        "Hand Style",
                        "Hand visual look",
                        icon = null,
                        options = listOf(
                            ListUserStyleSetting.ListOption(
                                "classic_style", "Classic", icon = null
                            ),
                            ListUserStyleSetting.ListOption(
                                "modern_style", "Modern", icon = null
                            ),
                            ListUserStyleSetting.ListOption(
                                "gothic_style",
                                "Gothic",
                                icon = null
                            )
                        ),
                        listOf(Layer.TOP_LAYER)
                    )
                )
            )
        )
        val complicationSlots = ComplicationsManager(
            listOf(
                Complication.Builder(
                    /*id */ 0,
                    CanvasComplicationDrawable(
                        ComplicationDrawable(this),
                        watchState
                    ),
                    listOf(
                        ComplicationType.RANGED_VALUE,
                        ComplicationType.LONG_TEXT,
                        ComplicationType.SHORT_TEXT,
                        ComplicationType.MONOCHROMATIC_IMAGE,
                        ComplicationType.SMALL_IMAGE
                    ),
                    DefaultComplicationProviderPolicy(SystemProviders.DAY_OF_WEEK)
                ).setUnitSquareBounds(RectF(0.15625f, 0.1875f, 0.84375f, 0.3125f))
                    .setDefaultProviderType(ComplicationType.SHORT_TEXT)
                    .build(),
                Complication.Builder(
                    /*id */ 1,
                    CanvasComplicationDrawable(
                        ComplicationDrawable(this),
                        watchState
                    ),
                    listOf(
                        ComplicationType.RANGED_VALUE,
                        ComplicationType.LONG_TEXT,
                        ComplicationType.SHORT_TEXT,
                        ComplicationType.MONOCHROMATIC_IMAGE,
                        ComplicationType.SMALL_IMAGE
                    ),
                    DefaultComplicationProviderPolicy(SystemProviders.STEP_COUNT)
                ).setUnitSquareBounds(RectF(0.1f, 0.5625f, 0.35f, 0.8125f))
                    .setDefaultProviderType(ComplicationType.SHORT_TEXT)
                    .build()
            ),
            userStyleRepository
        )

        val renderer = object : CanvasRenderer(
            surfaceHolder,
            userStyleRepository,
            watchState,
            CanvasType.HARDWARE
        ) {
            init {
                userStyleRepository.addUserStyleListener(
                    object : UserStyleRepository.UserStyleListener {
                        override fun onUserStyleChanged(userStyle: UserStyle) {
                            // `userStyle` will contain two userStyle categories with options
                            // from the lists above. ...
                        }
                    })
            }

            override fun render(
                canvas: Canvas,
                bounds: Rect,
                calendar: Calendar
            ) {
                // ...
            }
        }

        return WatchFace.Builder(
            WatchFaceType.ANALOG,
            /* interactiveUpdateRateMillis */ 16,
            userStyleRepository,
            complicationSlots,
            renderer,
            watchFaceHost,
            watchState
        ).build()
    }
}

return ExampleCanvasWatchFaceService()

Base classes for complications and styles are provided along with a default UI for configuring them. Complications are optional, however if required, WatchFaceService assumes all complications can be enumerated up front and passed as a collection into WatchFace's constructor. Some watch faces support different configurations (number & position) of complications and this can be achieved by rendering a subset and only marking the ones you need as active. Most watch faces will not animate the location of complications so its recommended to use the WatchFace.UnitSquareBoundsProvider helper.

Many watch faces support styles, typically controlling the color and visual look of watch face elements such as numeric fonts, watch hands and ticks. WatchFaceService doesn't take an an opinion on what comprises a style beyond it should be representable as a map of categories to options.

It's recommended to avoid putting business logic in sub classes of WatchFaceService, rather that should go in sub classes of WatchFace.

To aid debugging watch face animations, WatchFaceService allows you to speed up or slow down time, and to loop between two instants. This is controlled by MOCK_TIME_INTENT intents with a float extra called "androidx.wear.watchface.extra.MOCK_TIME_SPEED_MULTIPLIE" and to long extras called "androidx.wear.watchface.extra.MOCK_TIME_WRAPPING_MIN_TIME" and "androidx.wear.watchface.extra.MOCK_TIME_WRAPPING_MAX_TIME" (which are UTC time in milliseconds). If minTime is omitted or set to -1 then the current time is sampled as minTime.

E.g, to make time go twice as fast: adb shell am broadcast -a androidx.wear.watchface.MockTime --ef androidx.wear.watchface.extra.MOCK_TIME_SPEED_MULTIPLIER 2.0

To use the default watch face configuration UI add the following into your watch face's AndroidManifest.xml:

<activity
  android:name="androidx.wear.watchface.ui.WatchFaceConfigActivity"
  android:exported="true"
  android:label="Config"
  android:theme="@android:style/Theme.Translucent.NoTitleBar">
  <intent-filter>
    <action android:name="com.google.android.clockwork.watchfaces.complication.CONFIG_DIGITAL" />
      <category android:name=
           "com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION" />
      <category android:name="android.intent.category.DEFAULT" />
   </intent-filter>
</activity>

To register a WatchFaceService with the system add a tag to the in your watch face's AndroidManifest.xml:

<service
  android:name=".MyWatchFaceServiceClass"
  android:exported="true"
  android:label="@string/watch_face_name"
  android:permission="android.permission.BIND_WALLPAPER">
  <intent-filter>
    <action android:name="android.service.wallpaper.WallpaperService" />
    <category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
  </intent-filter>
  <meta-data
     android:name="com.google.android.wearable.watchface.preview"
     android:resource="@drawable/my_watch_preview" />
  <meta-data
    android:name="com.google.android.wearable.watchface.preview_circular"
    android:resource="@drawable/my_watch_circular_preview" />
  <meta-data
    android:name="com.google.android.wearable.watchface.wearableConfigurationAction"
    android:value="com.google.android.clockwork.watchfaces.complication.CONFIG_DIGITAL"/>
  <meta-data
    android:name="android.service.wallpaper"
    android:resource="@xml/watch_face" />
</service>

Multiple watch faces can be defined in the same package, requiring multiple tags.

Summary

Public constructors

WatchFaceService and WatchFace are a pair of base classes intended to handle much of the boilerplate needed to implement a watch face without being too opinionated.

Public methods
Engine

Protected methods
abstract WatchFace
createWatchFace(surfaceHolder: SurfaceHolder, watchFaceHost: WatchFaceHost, watchState: WatchState)

Override this factory method to create your WatchFace.

Inherited extension functions
From androidx.datastore.android.content.Context
DataStore<T>
Context.createDataStore(fileName: String, serializer: Serializer<T>, corruptionHandler: ReplaceFileCorruptionHandler<T>? = null, migrations: List<DataMigration<T>> = listOf(), scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob()))

Create an instance of SingleProcessDataStore.

From androidx.datastore.preferences.android.content.Context
DataStore<Preferences>
Context.createDataStore(name: String, corruptionHandler: ReplaceFileCorruptionHandler<Preferences>? = null, migrations: List<DataMigration<Preferences>> = listOf(), scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob()))

Create an instance of SingleProcessDataStore.

From androidx.core.content.android.content.Context
T?

Return the handle to a system-level service by class.

Unit
Context.withStyledAttributes(set: AttributeSet? = null, attrs: IntArray, @AttrRes defStyleAttr: Int = 0, @StyleRes defStyleRes: Int = 0, block: TypedArray.() -> Unit)

Executes block on a TypedArray receiver.

Unit
Context.withStyledAttributes(@StyleRes resourceId: Int, attrs: IntArray, block: TypedArray.() -> Unit)

Executes block on a TypedArray receiver.

Public constructors

<init>

WatchFaceService()

WatchFaceService and WatchFace are a pair of base classes intended to handle much of the boilerplate needed to implement a watch face without being too opinionated. The suggested structure of an WatchFaceService based watch face is:

import android.graphics.RectF
import androidx.wear.complications.DefaultComplicationProviderPolicy
import androidx.wear.watchface.complications.rendering.ComplicationDrawable
import androidx.wear.watchface.CanvasComplicationDrawable
import androidx.wear.watchface.ComplicationsManager
import androidx.wear.watchface.style.ListUserStyleSetting
import androidx.wear.watchface.style.UserStyleRepository
import androidx.wear.watchface.style.UserStyleSchema

class ExampleCanvasWatchFaceService : WatchFaceService() {
    override fun createWatchFace(
        surfaceHolder: SurfaceHolder,
        watchFaceHost: WatchFaceHost,
        watchState: WatchState
    ): WatchFace {
        val userStyleRepository = UserStyleRepository(
            UserStyleSchema(
                listOf(
                    ListUserStyleSetting(
                        "color_style_setting",
                        "Colors",
                        "Watchface colorization",
                        icon = null,
                        options = listOf(
                            ListUserStyleSetting.ListOption(
                                "red_style",
                                "Red",
                                icon = null
                            ),
                            ListUserStyleSetting.ListOption(
                                "green_style",
                                "Green",
                                icon = null
                            ),
                            ListUserStyleSetting.ListOption(
                                "bluestyle",
                                "Blue",
                                icon = null
                            )
                        ),
                        listOf(Layer.BASE_LAYER, Layer.COMPLICATIONS, Layer.TOP_LAYER)
                    ),
                    ListUserStyleSetting(
                        "hand_style_setting",
                        "Hand Style",
                        "Hand visual look",
                        icon = null,
                        options = listOf(
                            ListUserStyleSetting.ListOption(
                                "classic_style", "Classic", icon = null
                            ),
                            ListUserStyleSetting.ListOption(
                                "modern_style", "Modern", icon = null
                            ),
                            ListUserStyleSetting.ListOption(
                                "gothic_style",
                                "Gothic",
                                icon = null
                            )
                        ),
                        listOf(Layer.TOP_LAYER)
                    )
                )
            )
        )
        val complicationSlots = ComplicationsManager(
            listOf(
                Complication.Builder(
                    /*id */ 0,
                    CanvasComplicationDrawable(
                        ComplicationDrawable(this),
                        watchState
                    ),
                    listOf(
                        ComplicationType.RANGED_VALUE,
                        ComplicationType.LONG_TEXT,
                        ComplicationType.SHORT_TEXT,
                        ComplicationType.MONOCHROMATIC_IMAGE,
                        ComplicationType.SMALL_IMAGE
                    ),
                    DefaultComplicationProviderPolicy(SystemProviders.DAY_OF_WEEK)
                ).setUnitSquareBounds(RectF(0.15625f, 0.1875f, 0.84375f, 0.3125f))
                    .setDefaultProviderType(ComplicationType.SHORT_TEXT)
                    .build(),
                Complication.Builder(
                    /*id */ 1,
                    CanvasComplicationDrawable(
                        ComplicationDrawable(this),
                        watchState
                    ),
                    listOf(
                        ComplicationType.RANGED_VALUE,
                        ComplicationType.LONG_TEXT,
                        ComplicationType.SHORT_TEXT,
                        ComplicationType.MONOCHROMATIC_IMAGE,
                        ComplicationType.SMALL_IMAGE
                    ),
                    DefaultComplicationProviderPolicy(SystemProviders.STEP_COUNT)
                ).setUnitSquareBounds(RectF(0.1f, 0.5625f, 0.35f, 0.8125f))
                    .setDefaultProviderType(ComplicationType.SHORT_TEXT)
                    .build()
            ),
            userStyleRepository
        )

        val renderer = object : CanvasRenderer(
            surfaceHolder,
            userStyleRepository,
            watchState,
            CanvasType.HARDWARE
        ) {
            init {
                userStyleRepository.addUserStyleListener(
                    object : UserStyleRepository.UserStyleListener {
                        override fun onUserStyleChanged(userStyle: UserStyle) {
                            // `userStyle` will contain two userStyle categories with options
                            // from the lists above. ...
                        }
                    })
            }

            override fun render(
                canvas: Canvas,
                bounds: Rect,
                calendar: Calendar
            ) {
                // ...
            }
        }

        return WatchFace.Builder(
            WatchFaceType.ANALOG,
            /* interactiveUpdateRateMillis */ 16,
            userStyleRepository,
            complicationSlots,
            renderer,
            watchFaceHost,
            watchState
        ).build()
    }
}

return ExampleCanvasWatchFaceService()

Base classes for complications and styles are provided along with a default UI for configuring them. Complications are optional, however if required, WatchFaceService assumes all complications can be enumerated up front and passed as a collection into WatchFace's constructor. Some watch faces support different configurations (number &amp; position) of complications and this can be achieved by rendering a subset and only marking the ones you need as active. Most watch faces will not animate the location of complications so its recommended to use the WatchFace.UnitSquareBoundsProvider helper.

Many watch faces support styles, typically controlling the color and visual look of watch face elements such as numeric fonts, watch hands and ticks. WatchFaceService doesn't take an an opinion on what comprises a style beyond it should be representable as a map of categories to options.

It's recommended to avoid putting business logic in sub classes of WatchFaceService, rather that should go in sub classes of WatchFace.

To aid debugging watch face animations, WatchFaceService allows you to speed up or slow down time, and to loop between two instants. This is controlled by MOCK_TIME_INTENT intents with a float extra called "androidx.wear.watchface.extra.MOCK_TIME_SPEED_MULTIPLIE" and to long extras called "androidx.wear.watchface.extra.MOCK_TIME_WRAPPING_MIN_TIME" and "androidx.wear.watchface.extra.MOCK_TIME_WRAPPING_MAX_TIME" (which are UTC time in milliseconds). If minTime is omitted or set to -1 then the current time is sampled as minTime.

E.g, to make time go twice as fast: adb shell am broadcast -a androidx.wear.watchface.MockTime --ef androidx.wear.watchface.extra.MOCK_TIME_SPEED_MULTIPLIER 2.0

To use the default watch face configuration UI add the following into your watch face's AndroidManifest.xml:

<activity
  android:name="androidx.wear.watchface.ui.WatchFaceConfigActivity"
  android:exported="true"
  android:label="Config"
  android:theme="@android:style/Theme.Translucent.NoTitleBar">
  <intent-filter>
    <action android:name="com.google.android.clockwork.watchfaces.complication.CONFIG_DIGITAL" />
      <category android:name=
           "com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION" />
      <category android:name="android.intent.category.DEFAULT" />
   </intent-filter>
</activity>

To register a WatchFaceService with the system add a tag to the in your watch face's AndroidManifest.xml:

<service
  android:name=".MyWatchFaceServiceClass"
  android:exported="true"
  android:label="@string/watch_face_name"
  android:permission="android.permission.BIND_WALLPAPER">
  <intent-filter>
    <action android:name="android.service.wallpaper.WallpaperService" />
    <category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
  </intent-filter>
  <meta-data
     android:name="com.google.android.wearable.watchface.preview"
     android:resource="@drawable/my_watch_preview" />
  <meta-data
    android:name="com.google.android.wearable.watchface.preview_circular"
    android:resource="@drawable/my_watch_circular_preview" />
  <meta-data
    android:name="com.google.android.wearable.watchface.wearableConfigurationAction"
    android:value="com.google.android.clockwork.watchfaces.complication.CONFIG_DIGITAL"/>
  <meta-data
    android:name="android.service.wallpaper"
    android:resource="@xml/watch_face" />
</service>

Multiple watch faces can be defined in the same package, requiring multiple tags.

Public methods

onCreateEngine

fun onCreateEngine(): Engine

Protected methods

createWatchFace

protected abstract fun createWatchFace(
    surfaceHolder: SurfaceHolder,
    watchFaceHost: WatchFaceHost,
    watchState: WatchState
): WatchFace

Override this factory method to create your WatchFace.