Category Archives

3 Articles
Implementing the new ambient second hand for Wear OS with Watch Face Decompositions

Implementing the new ambient second hand for Wear OS with Watch Face Decompositions

The Wear OS team seems to have become more and more negligent about releasing resources for developers. An update to the emulator with the new UI and H update was released a week after some watches got the update.

Now with the new Qualcom 3100 processor with the ability to have constant animations in ambient mode and up to 16 colors has been out for two months, there has still been no documentation on how to add this functionality to watch faces.

Finding the source

I originally tried to add this functionality by continuing to draw the second hand in ambient mode and increasing frame rate, but this used up tons of battery and I could tell this was not the way to go.

I decided to look at the WatchFaceService decompiled class and found a function that was not documented called updateDecomposition that receives a WatchFaceDecomposition object.

 What is Watch Face Decomposition?

There is another class called WatchFaceDecomposition that has a builder with several component types. Think of it kind of like how you would build a watch face in Facer if you have used that before. Different components are passed to the builder such as fonts, text, and images with different ids and z-indexes. There are several Base Types that can also be set to animate. These are as follows.

  • SMOOTH_SECOND_HAND
  • TICKING_SECOND_HAND
  • MINUTE_HAND
  • HOUR_HAND
  • BPH_21600_SECOND_HAND
  • BPH_28800_SECOND_HAND

The different components that can be added are:

  • Image Component: This can be used as a background or icon and can be set to rotate with one of the above hand presets and must have an Icon Drawable set
  • Font Component: Font components are set from a source image Icon Drawable with all the digits that will be used on an image from top to bottom and the number of digits in the image must also be supplied
  • Number Component: The font component can be set to a number component which can update using the same presets in the list above
  • Complication Component: All complications that should be visible can be added as a complication component. I haven’t had a chance to try this yet, but it seems pretty straight forward.
An example of the ambient second hand. I created a custom goals watch face based on the watch face that came with the Fossil Sport. I will release this if I ever get approved by the Play Store 🙁

How to Add to your watchface

Here is an example of the function I created to make a WatchFaceDecomposition:

private WatchFaceDecomposition createDecompositionWatchFace() {
ImageComponent ticksComponent = new ImageComponent.Builder()
.setComponentId(2)
.setZOrder(2)
.setImage(Icon.createWithBitmap(BitmapUtil.loadBitmap(getBaseContext(), “ticks_embossed_decomposable.png”)))
.setBounds(new RectF(0, 0, mCenterX * 2, mCenterY * 2))
.build();

ImageComponent hourHandComponent = new ImageComponent.Builder(HOUR_HAND)
.setComponentId(3)
.setZOrder(3)
.setImage(Icon.createWithBitmap(BitmapUtil.loadBitmap(getBaseContext(), “hour_hand_decomposable.png”)))
.setBounds(new RectF(0.46f, .23f, 0.5f, .75f))
.build();

ImageComponent minuteHandComponent = new ImageComponent.Builder(MINUTE_HAND)
.setComponentId(4)
.setZOrder(4)
.setImage(Icon.createWithBitmap(BitmapUtil.loadBitmap(getBaseContext(), “minute_hand_decomposable.png”)))
.setBounds(new RectF(0.455f, 0f, 0.5f, .75f))
.build();

ImageComponent secondHandComponent = new ImageComponent.Builder(TICKING_SECOND_HAND)
.setComponentId(5)
.setZOrder(5)
.setImage(Icon.createWithBitmap(BitmapUtil.loadBitmap(getBaseContext(), “second_hand_decomposable.png”)))
.setBounds(new RectF(0.46f, .03f, 0.5f, .75f))
.build();

return new WatchFaceDecomposition.Builder()
.addImageComponents(ticksComponent)
.addImageComponents(hourHandComponent)
.addImageComponents(minuteHandComponent)
.addImageComponents(secondHandComponent)
.build();
}

Now actually telling the watch face to display this is another matter, but pretty simple once you know how.

First, at the end of the onCreate method of the watch face engine, run the updateDecomposition function we mentioned earlier:

updateDecomposition(createDecompositionWatchFace());

Next we need to make a receiver class within the engine to update the decomposition occasionally. Running this function seems to black out the screen for a second so this should only be done when one of the components needs to be updated. The new processor seems to handle things like animation.

private class UpdateDecompositionReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Hubcaps.Engine.this.updateDecomposition(createDecompositionWatchFace());
}
}

Now in the watch face class outside the engine, we need to create an alarm that will wake up the watch face and re-build the decomposition watch face. We will start this when the watch face is created and stop it when destroyed

private AlarmManager alarmManager;
private PendingIntent decompositionPendingIntent;

private void startDecompositionAlarm() {
this.alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
decompositionPendingIntent = PendingIntent.getBroadcast(getBaseContext(), 0,
new Intent(getBaseContext(), Hubcaps.Engine.UpdateDecompositionReceiver.class), 0);
this.alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 3600000L,
3600000L, decompositionPendingIntent);
}

@Override
public void onCreate() {
super.onCreate();
startDecompositionAlarm();
}

@Override
public void onDestroy() {
super.onDestroy();
alarmManager.cancel(decompositionPendingIntent);
}

All done! This is a simple analog watch face I created for my Hubcaps watch face that you can see here if you have either the Montblanc Summit 2 or Fossil Sport.

Hubcaps Preview

I have already bugged lots of people for some official documentation, but in the meantime, I hope this helps. Look forward to seeing a lot of developers using this in their watch faces!