This codelab will introduce you to the key concepts to creating your own watch face for Android Wear. 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 Android Wear. At the end of the codelab, you can expect to have a watch face you can call your own.

Concepts

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

Android Wear 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 Android Wear 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!

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 https://github.com/googlecodelabs/watchface

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:

Click OK on "Import Project from Gradle" screen without making any changes. (You may see a dialog like the one below.)

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

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

Emulator setup

If you need help setting up an Android Wear emulator, please refer to the "Set Up an Android Wear Emulator or Device" section of the "Creating and Running a Wearable App" article.

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/com.android.example.watchface
Installing com.android.example.watchface
DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/com.android.example.watchface"
pkg: /data/local/tmp/com.android.example.watchface
Success

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.

Summary

In this step you've learned about:

Next up

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

Code step 2

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.

Prepare your image

The first step is to prepare the image. You can select any photograph of your choice, but note that some images with tiny details may not scale well on a small watch display. Crop it to a square shape and resize it to something like 600 x 600 pixels. It can be in JPEG or PNG format. The next step is to rename it to custom_background.jpg or custom_background.png (Android needs underscore in place of 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-nodpi.

If you do not have an image, go to res/drawable-nodpi directory under 2-background - copy the custom_background.jpg image to your res/drawable-nodpi under 1-base.

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.

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:

Summary

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.save();
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,
        mCenterY + HAND_END_CAP_RADIUS, 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);
canvas.restore();

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, 
    mHandPaint);

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.

Summary

In this step you've learned about:

Next up

In addition to interactive mode, Android Wear 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, Android Wear 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.getWidth(),
        mBackgroundBitmap.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(mGrayBackgroundBitmap);
    Paint grayPaint = new Paint();
    ColorMatrix colorMatrix = new ColorMatrix();
    colorMatrix.setSaturation(0);
    ColorMatrixColorFilter filter = new 
    ColorMatrixColorFilter(colorMatrix);
    grayPaint.setColorFilter(filter);
    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) {
    mHandPaint.setAntiAlias(false);
} else {
    mHandPaint.setAntiAlias(true);
}

invalidate();

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 Android Wear watches support:

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

@Override
public void onPropertiesChanged(Bundle properties) {
    super.onPropertiesChanged(properties);
    mLowBitAmbient = properties.getBoolean(
        PROPERTY_LOW_BIT_AMBIENT, false);
    mBurnInProtection = properties.getBoolean(
         PROPERTY_BURN_IN_PROTECTION, false);
}
if ((mAmbient && mLowBitAmbient) || (mAmbient && mBurnInProtection)){
    canvas.drawColor(Color.BLACK);
} else if (mAmbient) {
    canvas.drawBitmap(mGrayBackgroundBitmap, 0, 0, mBackgroundPaint);
} else {
    canvas.drawBitmap(mBackgroundBitmap, 0, 0, mBackgroundPaint);
}

if (!mBurnInProtection || !mLowBitAmbient) {

initGrayBackgroundBitmap();

}

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.

Summary

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 'com.android.support:palette-v7:23.3.0'

Palette.from(mBackgroundBitmap).generate(
    new Palette.PaletteAsyncListener() {
      public void onGenerated(Palette palette) {
        if (palette != null) {
          Log.d("onGenerated", palette.toString());
          mWatchHandColor = palette.getVibrantColor(Color.WHITE);
          mWatchHandShadowColor = 
              palette.getDarkMutedColor(Color.BLACK);
          
          setWatchHandColor();
        }
      }
});
private void setWatchHandColor(){
    if (mAmbient){
        mHandPaint.setColor(Color.WHITE);
        mHandPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, Color.BLACK);
    } else {
        mHandPaint.setColor(mWatchHandColor);
        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:

Summary

In this step you've learned about:

For more details about developing Android Wear 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 Android Wear 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