This codelab shows how easy it is to create your own Wear OS analog watch face using Kotlin DSL (domain-specific language). By the end of the codelab, you'll have a customized watch face that you can call your own.
If you run into any issues (code bugs, grammatical errors, unclear wording, etc.) as you work through this codelab, please report the issue via the Report a mistake link in the lower left corner of the codelab.
A domain-specific language (DSL) is a "language specialized to a particular application domain". A DSL is a way to deal with a specific set of concerns. In our case, it's used to help us create watch faces.
In this codelab, we show how to use a DSL to greatly simplify the creation of watch faces.
Let's start by learning a little about Wear OS and its most prominent UI element - the watch face.
Wear OS by Google is designed for small, powerful devices, worn on the body. It is designed to deliver useful information when you need it most, intelligent answers to spoken questions, and tools to help reach fitness goals.
Style is a big part of such a personal device. Aside from offering a choice of manufacturers, customisable watch faces give users even more ways to express their personal style, and we will help you create your own today.
A watch face is essentially a native service that runs in the background on a Wear OS device. Within this service, there is an engine that renders each screen. You can think of this as an animator flipping through a book of moving cartoon drawings.
You normally write code that manually draws each of these pages (making the watch face move). However, we will use Kotlin DSL to greatly simplify the process.
Let's get started!
To help you get you started quickly, we have prepared a project for you to build on. It contains some basic code and application settings necessary for building watch faces.
If you have Git installed, run the command below. (You can check by typing git --version
in the terminal / command line and verify that it executes correctly.)
git clone https://github.com/googlecodelabs/watchface-kotlin
If you do not have git you can get the project as a zip file:
Start Android Studio and select "Open an existing Android Studio project" from the Welcome screen. Open the project directory and double click the build.gradle
file in the watchface-kotlin directory:
After the project has loaded, you may see an alert saying, "Unregistered VCS root detected". Click "Ignore" or the "X" in the upper-right corner. (You won't be pushing any changes back to the Git repo.)
In the upper-left corner of the project window, if you are in the Android view, you should see a set of folder icons similar to those in the screenshot below. (If you are in the Project view, expand the watchface-kotlin project to see the set of folder icons.)
There are two folder icons (base
and complete
). Each folder icon represents a "module". Please note that Android Studio might take several seconds to compile the project in the background for the first time. During this time you will see a spinner in the status bar at the bottom of Android Studio:
Wait until the processes finishes before making code changes, to allow Android Studio to pull in all the necessary components.
In addition, if you get a prompt saying "Reload for language changes to take effect?" or something similar, select "Yes".
You're ready to create a watch face. You'll start in the base
module and build a watch face on top of that code. You'll add code from each step to base
.
The complete
module can be used for checking your work, or for you to reference if you encounter any issues.
Overview of key components:
AnalogDslWatchFace
- Code used to create and style the watch face. This file is located in the directory base/java/com.example.android.watchface.watchfacekotlin
.res/drawable/
- Directory containing watch face background image.If you do not have a Wear OS device and need help setting up a Wear OS emulator, please refer to Launch a Wear emulator and run your Wear app.
Let's run the watch face on a watch.
base
configuration from the drop-down selector and click the green triangle (Run) button next to it:Activity
(instructions below).Activity
to use when launching the app, choose "Do not launch Activity".Activity
(if necessary, from the previous step), click the drop-down selector to the left of the green arrow and click "edit configurations".base
and you will see a window similar the one below. Under the "Launch Options" section, there will be a set of dropdown options. Select "Nothing" under the "Launch Options" section and click OK. Once the prompt dismisses, you will need to click the green triangle again to run the program. Later, if you want to try launching any of the other modules, you will need to do this as well.$ adb install-multiple -r -t ... lots of stuff ... Split APKs installed
Please note, since this is the first time you are running this watch face, you will need to select it from "See more watch faces". After it has been selected once, it will show up as one of the options alongside this option.
04-27 15:40:00.879 14459-14459/com.example.android.watchface.watchfacekotlin E/AndroidRuntime: FATAL EXCEPTION: main
...
Caused by: java.lang.InstantiationException: Must define watch face styles in DSL.
at com.example.android.watchface.watchfacekotlin.service.AnalogWatchFaceStyleBuilder.build(WatchFaceStyleDsl.kt:146)
at
....
Don't worry if your emulator has a cloud with a strikethrough in place of the airplane icon. We will not need a connection to a phone / internet for this code lab.
In this step you've learned about:
Let's start making this watch face our own.
In this section, you will create watch hands and color for your watch face.
Just kidding, using Kotlin + DSL will help us avoid manual painting canvases in this codelab!
In the base
module, open the AnalogDslWatchFace
file and look at analogWatchFaceStyle {}
. It should look like this:
return analogWatchFaceStyle { }
Let's define the colors:
color
watchFaceColors
. Select that and Android Studio will populate your DSL.main
inside watchFaceColors
. Again, Android Studio should auto-populate this for you.color = Color.Green
. You should now have something that looks like this:return analogWatchFaceStyle {
watchFaceColors {
main = Color.GREEN
}
}
Now that we have the main color set, let's define the length of the hour, minute, and second watch arms:
watchFaceColors
, start typing dimensions
watchFaceDimensions
. Select that and Android Studio will populate your DSL with the proper code for dimensions.watchFaceDimensions
, start typing "hour" and choose hourHandRadiusRatio
.0.2f
(requires a float).return analogWatchFaceStyle {
watchFaceColors {
main = Color.GREEN
}
watchFaceDimensions {
hourHandRadiusRatio = 0.2f
minuteHandRadiusRatio = 0.5f
secondHandRadiusRatio = 0.9f
}
}
Choose the Kotlin DSL Analog watch face in the Favorites menu:
You should see something like this:
Let's customize more colors in our watch face:
watchFaceColors
, type highlight
and click the suggestion. Set that field to Color.parseColor("#BB0000")
. background
and click the suggestion. Set that field to Color.WHITE
or whatever color you want.return analogWatchFaceStyle {
watchFaceColors {
main = Color.GREEN
highlight = Color.parseColor("#BB0000")
background = Color.WHITE
}
watchFaceDimensions {
hourHandRadiusRatio = 0.2f
minuteHandRadiusRatio = 0.5f
secondHandRadiusRatio = 0.9f
}
}
If you run the watch face now and reselect Kotlin DSL Analog, you should see a watch face similar to the image below.
In this step, you've learned:
We will further customize our watch face by setting a background image.
In this step, we add a background image to our watch face. If at any point you are confused by the concepts discussed here, please refer to the complete
module and see how these steps may be implemented.
A background image is supplied in this code lab. However, you can prepare your own image.
To use your own image, select any photograph, but note that some images with tiny details may not scale well on a small watch display. Crop the image to a square shape and resize it to about 600 x 600 pixels, depending on the target density of the screen. It can be in JPEG or PNG format. Then rename it to background_image.jpg
or background_image.png
(Android needs an underscore in place of a space).
After you completed this, "right click" the res/drawable
directory in Android Studio and select "Reveal in Finder" (for Mac) or "Show in Explorer" (for Windows). Copy your image file into the directory res/drawable. It will replace the default image already in the folder.
Open the AnalogDslWatchFace
file and look again at analogWatchFaceStyle {}
. It should look like this:
return analogWatchFaceStyle {
watchFaceColors {
main = Color.GREEN
highlight = Color.parseColor("#BB0000")
background = Color.WHITE
}
watchFaceDimensions {
hourHandRadiusRatio = 0.2f
minuteHandRadiusRatio = 0.5f
secondHandRadiusRatio = 0.9f
}
}
Let's add a background image:
watchFaceDimensions
, type background
and click the suggestion watchFaceBackgroundImage
.watchFaceBackgroundImage
, type background
again and click the suggestion backgroundImageResource
and set it equal to R.drawable.background_image
.watchFaceColors
to better match the new background image.main
to Color.CYAN
and the highlight
to #ffa500
.return analogWatchFaceStyle {
watchFaceColors {
main = Color.CYAN
highlight = Color.parseColor("#ffa500")
background = Color.WHITE
}
watchFaceDimensions {
hourHandRadiusRatio = 0.2f
minuteHandRadiusRatio = 0.5f
secondHandRadiusRatio = 0.9f
}
watchFaceBackgroundImage {
backgroundImageResource = R.drawable.background_image
}
}
If you run the watch face now and reselect Kotlin DSL Analog, you should see something like the image below.
In this step you've learned to:
Try customizing your watch face even further using DSL by reviewing all the options in the model/AnalogWatchFaceStyleModels.kt
class.
As stated earlier, DSLs (domain-specific languages) are "languages specialized to a particular application domain". To learn more about Kotlin DSL, read the Type-Safe Builders page on the Kotlin site.
You can see how the watch face DSL was implemented for this code lab by reviewing the service/WatchFaceStyleDsl.kt
class.
If you are interested in how the object that was created with DSL is rendered into a watch face, review the service/AbstractKotlinWatchFace.kt
class.
For more details about developing Wear OS watch faces and data providers (and how Java development compares to this code lab), please review
It's worthwhile to note that the implementation of this watch face has differing behavior in ambient mode, depending on the device's screen properties. On screens that require burn-in protection, the background is always black, whereas for other screens the watch face converts our bitmap into grayscale (or uses the background color if no bitmap was provided).
To learn more, read about respecting the device's screen properties. You can find how these properties are used in your watch face in the service/AbstractKotlinWatchFace.tk
class.
Watch these great videos: