This codelab will introduce you to the key concepts needed to create your own watch face for Wear OS. It will then walk you through customising an analog watch face. There is also a bonus section on using the palette API to automatically choose a color for the watch face if you have the time. By the end of the codelab, you'll have a customized watch face that you can call your own.

Concepts and setup

In this codelab, you'll learn how to quickly create a watch face for Wear OS. At the end of the codelab, you can expect to have a watch face you can call your own.


To start off let's learn a little bit about Wear OS and its most prominent UI element - the watch face.


Wear OS is a wearable platform 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.

Being such a personal device, style is a big part of it. Aside from offering a choice of manufacturers, customisable watch faces give users even more ways to express their personal style. This is what we are going to create today.

A watch face is essentially a native service that runs in the background on an 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. Our code will fill each of these pages, making the watch face move.

So let's get started!

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.

Clone the starter project repo

To get you started as quickly as possible, we have prepared a starter project for you to build on. It contains some basic code and application settings necessary for building watch faces. If you have git installed, you can simply run the command below. (You can check by typing git --version in the terminal / command line and verify it executes correctly.)

 git clone

If you do not have git you can get the project as a zip file:

Download Zip

Import the project

Start Android Studio, and select "Open an existing Android Studio project" from the Welcome screen, open the project directory and double click on the build.gradle file in the watchface directory:

After the project has loaded, you may also see an alert like the one below, you can click "X" in the upper right. (You won't be pushing any changes back to the Git repo.)

Screen Shot 2016-05-17 at 10.17.48 AM.png

In the upper-left corner of the project window, you should see something like the image below if you are in the Android view. (If you are in the Project view, you will need to expand the watchface project to see the same thing.)

There are five folder icons. Each of them are known as 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:

We recommend that you wait until this has finished before making code changes. This will 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".

Understand the starter project

All right, you're set up and ready to start creating your own watch face. We'll set off using the 1-base module, which is the starting point for the watch face that we'll be building upon. You will be adding code from each step to 1-base.

Each of the following modules can be used as reference points to check your work or for reference if you encounter any issues. The number in front of the module name corresponds with the codelab step.

Overview of key components

Run the starter project

Let's run it on a watch.

Waiting for device.
Target device: lge-urbane_2-XXXXXXXXXXXXXX
Uploading file
        local path: ~/Downloads/watchface/1-base/build/outputs/apk/1-base-debug.apk
        remote path: /data/local/tmp/
DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/"
pkg: /data/local/tmp/

Here's what it should look like. Don't worry if your emulator has a cloud with a strikethrough in place of the aeroplane icon. We will not need connection to a phone / internet for this code lab. Also note that the power button to the right might not appear - this is okay!

Additional background information - not necessary for code lab

Watch face templates are available in Android Studio and make it really simple to add watch faces to an existing application. To add watch faces to an existing project:

The resulting project will be very similar to "1-base" module in this code lab.


In this step you've learned about:

Next up

Let's start making this watch face our own by changing the background.

In this step, we will start making the watch face our own by giving it a background. If at any point you are confused by the concepts discussed here, please refer to the 2-background module and see how these steps may be implemented.

Create Bitmap and Paint objects

Before we can display the bitmap, we need to load and instantiate the object. Since we only want to do this once and we don't need the dimension of the screen, we can put this into the onCreate method.

Let's change the files in the 1-base module:

mBackgroundBitmap = BitmapFactory
    .decodeResource(getResources(), R.drawable.custom_background);

Resize the Bitmap object

Next we are going to resize the background bitmap. Since dimensions are not available in onCreate, we resize the Bitmap in onSurfaceChanged:

mScale = ((float) width) / (float) mBackgroundBitmap.getWidth();
mBackgroundBitmap = Bitmap.createScaledBitmap
    (mBackgroundBitmap, (int)(mBackgroundBitmap.getWidth() * mScale),
    (int)(mBackgroundBitmap.getHeight() * mScale), true);

Draw the background

Now that the bitmap is correctly sized - let's draw it!

canvas.drawBitmap(mBackgroundBitmap, 0, 0, mBackgroundPaint);

Run the watch face again

In the first step, you learned how to install the watch face to your device or emulator. Now it's time to do that again! Your watch face should look something like this:


In this step you've learned about:

Next up

Let's refine the watch arms!

Code step 3

While the current watch hands get the job done, we want to give the watch hands a more premium makeover. In this section, you will learn more about drawing on Android canvas.

Prepare the paint objects

Before an artist starts, they need to mix their color palette and ready their brush. This is what we will be doing:

Calculate the length of the watch hands

Different watches may have different size screens. Next to scaling the background, as we did in the last step, we also need to work out the watch hand lengths. Since screen dimensions do not change, we can insert the calculation code into the method onSurfaceChanged:

Draw the watch hands

Now that all the length calculation is done, it's time to draw the watch hands. In this section, we will walk you through the code to rotate the watch hands using canvas.rotate rather than using sine and cosine. This simplifies the code tremendously reducing the chance for error, allows more complex layouts as we will see later and leaves the optimisation to Android.

First of all we will prepare the canvas for the first hand we draw - the hour hand. So in the onDraw method:;
canvas.rotate(hoursRotation, mCenterX, mCenterY);

The rotate command above means that we have rotated the canvas counter-clockwise by the desired amount. This means we can just draw the hour hand in an upright direction rather than at an angle.

In addition, for our hour hand, instead of a line, we want to draw a hollow paper clip like shape for our watch hands. Before we begin, we need to think a little bit about our design:

To draw the watch hands:

private void drawHand(Canvas canvas, float handLength) {
    canvas.drawRoundRect(mCenterX - HAND_END_CAP_RADIUS,
        mCenterY - handLength, mCenterX + HAND_END_CAP_RADIUS,
        HAND_END_CAP_RADIUS, mHandPaint);
drawHand(canvas, mHourHandLength);
canvas.rotate(minutesRotation - hoursRotation, mCenterX, mCenterY);
drawHand(canvas, mMinuteHandLength);
canvas.drawLine(mCenterX, mCenterY - HAND_END_CAP_RADIUS, mCenterX,
    mCenterY - mSecondHandLength, mHandPaint);

How to check your progress and debug

If you run the watch face now, you should see something like this:

Check that:


It is easy to make mistakes in calculating the rotation angle or setting the center of rotation. If these look odd consider logging these variables and checking the calculation by using

Log.d("MyWatchFaceService", "variable_you_want_to_log: " + variable_you_want_to_log);

and checking that the value makes sense. For primitives such as int or float, these can be logged directly as shown. For objects such as mCalendar, you will need to log its String representation by logging mCalendar.toString() rather than logging mCalendar. Otherwise,the code will not compile as the method is looking for a String object rather than a Calendar object.

Before publishing your watch face, we recommend that developers test their design in their daily lives and see that it both works correctly technically and that the design works in all circumstances (indoor / outdoor / stationary / on-the-move).

Perfect the center

Coming back to the current design, you might notice that at the center the shadow of the second hand is on top of the hour hand, and it looks a little out of place. A solution is to add a hollow circle in the middle above the second hand to solve this:

canvas.drawCircle(mCenterX, mCenterY, HAND_END_CAP_RADIUS, 

If you run the watch face again, it should look something like this:

Change the preview image in the watch face selector

In the watch face selector, you can see a preview of the watch face. This can be changed by replacing the preview image - preview_analog.png in the res/drawable-nodpi directory.


In this step you've learned about:

Next up

In addition to interactive mode, Wear OS watches also have an ambient mode which normally has a more discreet design and is only updated once a minute. In the next section, we will learn about how to deal with this.

Code step 4

Aside from the interactive mode, Wear OS also has an ambient mode. Ambient mode helps the device conserve power. We typically recommend developers use black, white, and grays in this mode. Developers may also use limited color but the design should clearly signal that the watch is in ambient mode.

Aside from color differences, another way that ambient mode is different is that the watch face will only be updated once a minute. As a result, screen elements which update more often such as animation or seconds hand should be removed in this mode.

React to ambient mode

Within the MyWatchFace.Engine class, there is a method called onAmbientModeChanged. This method will be called when the watch is going into or out of ambient mode. This gives you a chance to change the design.

For our watch face, we will do three things to the watch face if it does go into ambient mode:

  1. Change the background to be grayscale
  2. Remove anti-aliasing of the watch hand paints
  3. Remove the seconds hand

For 1, we can do this by creating a copy of the bitmap and apply a grayscale filter to it:

private void initGrayBackgroundBitmap() {
    mGrayBackgroundBitmap = Bitmap.createBitmap(
        mBackgroundBitmap.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(mGrayBackgroundBitmap);
    Paint grayPaint = new Paint();
    ColorMatrix colorMatrix = new ColorMatrix();
    ColorMatrixColorFilter filter = new 
    canvas.drawBitmap(mBackgroundBitmap, 0, 0, grayPaint);
if (mAmbient) {
    canvas.drawBitmap(mGrayBackgroundBitmap, 0, 0, mBackgroundPaint);
} else {
    canvas.drawBitmap(mBackgroundBitmap, 0, 0, mBackgroundPaint);

For 2, we add the following code into onAmbientModeChanged to switch anti-aliasing on and off.

mAmbient = inAmbientMode;

if (inAmbientMode) {
} else {


For 3, we update the code in onDraw to put a condition to check if mAmbient is false around the code that rotates and draw the seconds hand. This ensures that the seconds hand is only drawn in interactive mode. This is because the watch face is usually only updated once a minute in ambient mode.

Run the watch face. If you have an emulator, press F7 to toggle between interactive and ambient mode on your keyboard. If you have a physical device, cover the display with your hand. You should see that your watch face looks something like this:

Account for special screens

In additional to LCD screens, some Wear OS watches support:

To keep things simple, we will switch off the background if either of these modes are detected:

public void onPropertiesChanged(Bundle properties) {
    mLowBitAmbient = properties.getBoolean(
    mBurnInProtection = properties.getBoolean(
if ((mAmbient && mLowBitAmbient) || (mAmbient && mBurnInProtection)){
} else if (mAmbient) {
    canvas.drawBitmap(mGrayBackgroundBitmap, 0, 0, mBackgroundPaint);
} else {
    canvas.drawBitmap(mBackgroundBitmap, 0, 0, mBackgroundPaint);

if (!mBurnInProtection || !mLowBitAmbient) {



If you run this code on a supported device (e.g. Sony Smartwatch 3 for low-bit ambient mode and LG Watch Urbane 2nd Edition for burn-in protection mode), it should look like the following picture. For the purpose of this code lab, it is okay not to test this. For production, we recommend that you test against devices with these different screens.


In this step you've learned about:

Next up

An optional activity to learn about how we can add automatic color selection into our code, so that the watch hand color will automatically work with the background.

If you still have time but don't fancy having a go at the palette API, we encourage you to alter the different parameters of the screen elements, for example, stroke size, the radius of the watch arms, color of the various screen element, etc. Let's see what you get!

Code step 5

The Palette API helps automatically select the accent color of a bitmap. We will be using this API for automatically selecting the color of the watch hands. Outside of watch faces, you can use it to generate dynamic color schemes based on the user's input and fulfil one of the creative visions of material design.

Determine key colors of a bitmap

We will need to initiate the Palette object, feed our background bitmap to it and get it to analyse the result:

compile ''

    new Palette.PaletteAsyncListener() {
      public void onGenerated(Palette palette) {
        if (palette != null) {
          Log.d("onGenerated", palette.toString());
          mWatchHandColor = palette.getVibrantColor(Color.WHITE);
          mWatchHandShadowColor = 
private void setWatchHandColor(){
    if (mAmbient){
        mHandPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, Color.BLACK);
    } else {
        mHandPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, mWatchHandShadowColor);

Run the watch face again

Your watch face should look something like this:

If you copy over the custom_background2 image from the module "5-palette" to "1-base" and change the backgroundResId to custom_background2, you should see a watch face similar to this:


In this step you've learned about:

For more details about developing Wear OS notification and apps:

Here are some of the common customisation steps for watch faces:

Positioning status icons, the charging icon (the lighting bolt), "Ok Google", etc.

Refer to the WatchFaceStyle.Builder documentation for various options from setting gravity to making a semi-transparent background so that they are readable against the watch face.

Putting the watch face on the Google Play Store

What about digital watch faces?

Use the Wear OS watch face template in Android Studio. This will help you get the skeleton code:

Learn More

Watch these great videos:

Take the Ubiquitous Computing Online course