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.
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.
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!
For Google I/O 2015, you can find the sample code inside
io2015-codelabs on the desktop, and then
wear/watchface. Before you start, open that folder.
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 check by typing
git --version in the terminal / command line and see if executes correctly).
git clone https://github.com/googlesamples/android-codelab-watchface.git
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 on the
build.gradle file in the watchface directory:
Click OK on "Import Project from Gradle" screen without making any changes.
In the upper left hand corner of the project window, you should see something like this:
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”.
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
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
MyWatchFaceService- Our watch face and it has a watch face engine called
MyWatchFaceService.Engine- This file is located in the directory
1-base/java/com/android/example/watchface. In Android Studio, this is located under
1-base/java/com.android.example.watchface. Within the Engine class, we will mainly be working on three methods:
onCreate- We will initiate new classes such as the bitmap image object for our background, etc. This code is run once when the Engine is first started.
onSurfaceChanged- This is the first time when we have the dimension of the screen. Armed with this new information, we can resize any screen element required for drawing. This code is also expected to only be run once at the start.
onDraw- The core of what we will be doing. It renders every frame on the watch face canvas. Since it runs on every frame, we will try to keep this as fast as possible - no image resizing or object creation here!
res/drawable-nodpi/- This is the directory where we will be placing some additional image files.
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.
Let's run it on a watch.
Waiting for device. Target device: sony-smartwatch_3-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!
Since Android Studio 1.1, we have added watch face templates, which 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:
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.
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 jpg or png format. The next step is to rename it to custom_background (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
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.
MyWatchFaceService.Engineclass. This enables other methods to get hold of the Bitmap to resize it and draw later.
MyWatchFaceService.Engineclass, we will instantiate the bitmap:
Next we are going to resize the background bitmap. Since dimensions are not available in onCreate, we resize the Bitmap in
onSurfaceChangedmethod) and the width of the background bitmap:
Now that the bitmap is correctly sized - let’s draw it!
onDraw. We suggest you place this code directly below the code we deleted in the last step.
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:
Let’s refine the watch arms!
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.
Before an artist starts, they need to mix their color palette and ready their brush. This is what we will be doing:
MyWatchFaceService.Engineand set it to 4. Remember to put an “
f” after the 4 to indicate that this is a float rather than an integer.
MyWatchFaceService.Engineand set it to 6. Remember the “
mHandPaintobject with the following parameters in onCreate:
Paint.Style.STROKE- this means we can draw an outline of shapes
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
0.5 * width / 2
0.7 * width / 2
0.9 * width / 2
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
canvas.drawLine()from the line
canvas.restore(). We will step you through putting in the new watch hand code in the following steps.
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:
drawHand.This will help us only deal with the
drawRoundRectcode once. If there are any mistakes, we can fix it in one place rather than two. For this method we need both the canvas and the length of the hand:
minuteRotation, with that we have “neutralised” the minute hand rotation and all we need to do in this step is to “neutralise” the hour hand rotation. Lastly, do not worry about the ambient mode code. We will add that in the next section.
If you run the watch face now, you should see something like this:
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
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 mTime, you will need to log its String representation by logging mTime.toString() rather than logging mTime. Otherwise,the code will not compile as the method is looking for a String object rather than a Time 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).
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:
If you run the watch face again, it should look something like this:
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:
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.
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.
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:
For 1, we can do this by creating a copy of the bitmap and apply a grayscale filter to it:
initGrayBackgroundBitmap()at the end of the method onSurfaceChanged. The method should do the following:
For 2, we add the following code into onAmbientModeChanged to switch anti-aliasing on and off.
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:
In the image above, you can see that there is a peek card saying “0 steps to…”. In this case, the interference with the watch face has not been too bad but in other cases, it may lead to misreading those messages. As a result, we recommend that developers at least put a black rectangle behind the peek card by adding the following:
MyWatchFaceService.Enginecalled mCardBounds. Remember to initialise it with new Rect(). Otherwise, when the code first refers to it, it will be null and crash.
onPeekCardPositionUpdatemethod in MyWatchFaceService.Engine:
If you run the watch face now, it should look like this:
More details (optional): The
onPeekCardPositionUpdate actually works in both ambient mode and interactive mode. In interactive mode, the system software takes care of drawing a rectangle behind the card so no work is required. You might ask what is the use of
onPeekCardPositionUpdate in interactive mode? With certain designs, by knowing the card boundary you can actually shrink the watch face to the top visible portion of the screen and eliminate all interference.
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:
MyWatchFaceService.Engineto keep tab of: 1) the low-bit screen mode:
mLowBitAmbientand 2) the burn-in protection screen mode:
onSurfaceChanged()method to only create the grayscale bitmap if the watch is not in low bit or burn in protection mode:
If you run this code on a supported device (e.g. Sony Smartwatch 3 for low-bit ambient mode and LG G Watch R 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:
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!
As part of the Android 5.0 Lollipop launch, we have added a Palette API which 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 - a new cross platform design language.
We will need to initiate the Palette object, feed our background bitmap to it and get it to analyse the result:
CanvasWatchFaceService.Engineto store the colors. Initiate them with
mBackgroundBitmaphas been loaded:
MyWatchFaceService.Engineto set the color of the watch hands
setWatchHandColor()method before invalidating the frame in
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
custom_background2, you should see a watch face similar to this:
In this step you’ve learned about:
For more details about developing Android Wear notification and apps:
For more details about developering Android Wear watch faces, visit https://developer.android.com/training/wearables/watch-faces/index.html
Here are some of the common customisation steps for watch faces:
DevBytes: Developing an Android Wear Watch Face
DevBytes: Watch Faces for Android Wear