How to build custom watch faces for Android wear

How to build custom watch faces for Android wear

eeshwar

Android Wear is a new platform for smart watches. The LG G Watch and the Samsung Gear Live were the first to adopt the platform, soon it will start appearing on more devices from a range of manufacturers.

To be a smart watch, you must first look like a watch. Each watch has a watch face, most show the time and date but some show extra information like the weather and battery status. Currently a few watch faces are provided with each watch, and they are designed by the manufacturers. You can freely change between them whenever you want. But what if you want more?

Unfortunately, Google has not yet released an official API to allow developers to build watch faces. However, there is a way to start developing watch faces now, which I will run through in this post. The watch face I will be developing will be very simple, as we will be working with the basics. For this tutorial we will be using Android Studio and the Android Wear emulator.

Let’s get stated

Create a new project, we will call the application ‘First Watch Face’ follow these steps when creating a new project:

1

For this tutorial we will not be touching the mobile section, but it’s required to allow the watch face to sync to a wearable device. So make sure both Wear, Phone and Tablet are checked.2Since we will not be doing anything on the Mobile, we will not require an activity for it, so go ahead and select ‘Add no Activity’.

3

All our work will happen on the wearable so let’s create a blank activity for it.4

Give your activity a name, and we will be ready to start.
5

Is it a watch face yet?

Now it’s time to start coding, Android Studio will have done a lot of the work for us, so we don’t have to do much. First we will need to change the AndroidManifest.xml file in the wear/src/main folder. By default our application is a Wear app that appears in the app list, but we can change that so it will appear in the list of watch faces.

We need to add android:allowEmbedded="true" to the activity.

Just before we add the intent-filter, add

<meta-data android:name="com.google.android.clockwork.home.preview" android:resource="@drawable/ic_launcher" />.

This is the image for the watch face preview, it is shown in the list of watch faces. We will change this later, for now it will be the default app icon.

And lastly we need to change the intent-filter from

android.intent.category.LAUNCHER

to

com.google.android.clockwork.home.category.HOME_BACKGROUND.

Can it tell me the time?

If you look in the wear/src/main folder you will see 3 files. The activity_my_watch_face.xml file, which decides which of the 2 watch faces to run, rect_activity_my_watch_face.xml or round_activity_my_watch_face.xml depending on which type of watch it is run on. We will be adding our XML to both these files so our watch will run on both.

Thankfully you don’t have to change much here, Android Studio has done all the hard work for us. We will now edit the round and rect XML files to add 2 labels, one to display the time and the other for the battery level:

<TextView
android:id="@+id/time"
android:textSize="30sp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="6:00pm"/>

<TextView
android:id="@+id/battery"
android:textSize="13sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/watch_time"
android:text="50%"/>

It’s showing me the wrong time!

It’s time edit some java files, MyWatchFace.java is where all the magic happens. Again, Android Studio has done all the basic stuff for us but there is a little bit of work to do and our watch face will be complete.

Let’s create 2 variables for both out labels:
private TextView time
private battery;

and initialise them when inflating the view:
time = (TextView) stub.findViewById(R.id.time);
battery = (TextView) stub.findViewById(R.id.battery);

Now we need to create a BroadcastReciever that will be triggered when ever our Intent is broadcast. Our first Intent is for changes in time:

private final static IntentFilter intentFilter;
static {
intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_TIME_TICK);
intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
intentFilter.addAction(Intent.ACTION_TIME_CHANGED);
}

And its corresponding BroadcastReciever:

private BroadcastReceiver timeInfoReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context arg0, Intent intent) {
time.setText(
new SimpleDateFormat("kk:mm")
.format(Calendar.getInstance().getTime()));
}
};

Now add the following when inflating the view to set it all up:

timeInfoReceiver.onReceive(MyWatchFace.this, registerReceiver(null, intentFilter));
registerReceiver(timeInfoReceiver, intentFilter);

Let’s do the same for the battery:

private BroadcastReceiver batteryInfoReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context arg0, Intent intent) {
battery.setText(String.valueOf(intent.getIntExtra(
BatteryManager.EXTRA_LEVEL, 0) + "%"));
}
};

And again, the following when inflating the view:

registerReceiver(batteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

You may now run the app, your first watch face is complete.

Polish it off

If you remember we set the preview of the watch face to the default app icon. Now that our watch face is complete we can replace it with the actual image. So go ahead and take a screenshot of your emulator and place the image in the wear/src/main/res/drawable folder. Let’s edit the AndroidManifest.xml again and replace

<meta-data android:name="com.google.android.clockwork.home.preview" android:resource="@drawable/ic_launcher" />

with

<meta-data android:name="com.google.android.clockwork.home.preview" android:resource="@drawable/<screenshot_image_name>" />

where <screenshot_image_name> is the name of the image.

Optimisation

There are few things that we can do to optimise the app still. Firstly, we need to make sure both BroadcastReceiver are destroyed when our watch face is. so let’s add the following to the onDestroy method:

unregisterReceiver(timeInfoReceiver);
unregisterReceiver(batteryInfoReceiver);

This will make sure they are not running unnecessarily in the background.

Now the last thing, I promise! You will notice that watch faces currently dim them self by going grey scale or something similar. Currently we can not do this exactly as the current watch faces do, due to the lack of official API. But we can do something similar, by making changes to our view on the onPause and onResume methods. Slightly unreliable, it is a usable method, although you will notice that the watch dims when starting a wearable app. Don’t forget our watch face is still technically an app so onPause will be called.

People have tried to replicate this behaviour, for example you can use DisplayManager, as described by Nicolas Pomepuy here.

Now you know

Your first watch face is complete. You can now take this knowledge and let your creativity take over. We would be interested to see what you come up with, be sure to show us your creations via Twitter or Facebook. If you have any questions, leave them in the comments below.

Leave a Reply

Your email address will not be published. Required fields are marked *