Making a watchface for Garmin devices
In case anyone hasn’t heard, Pluralsight Live is happening soon…
Saying I’m extremely excited may be an understatement. Whether it was the keynote speakers that were there, the private concert that we rocked to one night, the company that I went with, or a combination of all of those, Pluralsight Live 2017 was one of the highlights of my year. I’m very grateful that I can attend again, and to commemorate that fact, I decided to create a new face for my watch! Additionally, to keep with the learning spirit of Pluralsight, I’ve decided to document the creation of my watchface so that I can share lessons I’ve learned, as well as some general tips!
So, what exactly will this post be about, and what will it not be about?
This article will be about creating a super simple watchface for Garmin devices, using Garmin’s propriety language called Monkey C! I’ll discuss the general process I went through, some tips and tricks, as well as some pitfalls that I ran across. Unfortunately, when I say “super simple,” that means I’ll be talking about just the first face in the image above. I may discuss how I went from the simple face, to the more colorful face, in a future article.
This article will not be a guide on the best practices for Monkey C, nor will it be a guide demonstrating how to create a complex watchface. Honestly, it has been a long time since I wrote my first watchface from scratch, and the platform has changed drastically (for the better) since I wrote my first few faces back in 2015.
Additionally, I’m a Windows user, so the screenshots you see in this article will be taken on a Windows machine. You should be able to do everything I do though, the screens will just look slightly different.
Lastly, if all you are looking for is a list of tools that I’ve used, it’s at the bottom of this article. A link to the code for the fancier looking watchface will also be included at the end.
Step 1 — Design
First things first, it’s a good idea to have a design in mind. I’ve found that I retain knowledge around what a platform is capable of when I’m thinking in terms of what I want to accomplish with it. On the flip-side, it’s also important to know what a platform is capable of when making a design so that you don’t waste your time on impossible features. In the end, it’s a balancing act that you become better at as time goes on ¯\_(ツ)_/¯
When I’m designing watchfaces, I typically think of 4 things:
- Functionality
- Layout
- Font (keep in mind that font at smaller scales like this can impact final layout choices)
- Colors
Functionality
Garmin watches are pretty capable devices. They can last for weeks, can be seen in daylight, and they support many of the features people come to expect from other, more powerful Smartwatches. Given all of that, and given what people have asked me for in the past, I know that I want this watchface to show a few pieces of data:
- How much battery is left
- The user’s heartrate
- The current step count
- The current percent of step goal completion
- The count of phone notifications
- The date
- And of course, I want it to show the time
One important thing to note: not all Garmin watches have the same capabilities. I’ll cover how to handle that in a later section though.
Layout
I’ve found that designing a layout upfront makes the coding process go much quicker, as you can spend consecutive chunks of time programming instead of programming, then designing, and then programming some more. It’s all about focus.
Font and Colors
These are more items where the benefit of figuring out upfront is related to focus (please refer back to the Layout section for an explanation).
To talk about my Font and Color choices, I think the color scheme Pluralsight uses is pretty awesome, so I tried to stick close to that. I also really enjoy their fonts. As you can see in the bottom of the earlier picture, I have some hex values for colors written down. I retrieved these values from inspecting Pluralsight’s website. I also found what font they were using (Gotham), but it costs money to use that, so I’m going to have to come up with something else font-wise. I’ll cross that bridge later though.
Step 2 — Setting up your environment
One could make a pretty valid argument for why this should be Step 1, but I designed my watchface before I had my computer ready, so I’m going to leave this as Step 2. Maybe you could use the fact that you invested time in making a design to keep you focused on setting up your environment and finishing your project!
Garmin has a pretty in-depth tutorial on setting up your workspace for Mac, Linux, or Windows environments. You can find all of that here: https://developer.garmin.com/connect-iq/programmers-guide/getting-started/.
If you’re a Windows user and not afraid of Powershell/Chocolately, there is a script included in the repository for this watchface that automates most of the setup.
Step 3 — Making sure everything works
So, you’ve created a design, and you have your environment set up. Now is a good time to make sure that what you have works.
We can do this simply by creating a brand new project, and running it with Garmin’s device simulator.
To create a new project in Eclipse,
- Go to File → New → ConnectIQ project.
- Name your project appropriately, and put it somewhere where you’ll remember. Click next.
- For Project Type, choose Watchface. Leave the other values alone. Click next.
- For now, just choose Simple. Click next.
- If you want to have more screens match mine, choose Vivoactive for Target Platforms (this can easily be changed later).
- Click Finish.
Woo! You created your new watchface project! Now it is time to make sure it runs.
- First, go to Run → Run Configurations (you can also follow along with the Gif above, it shows a different way to get to the same screen).
- Right click on `Connect IQ App` and click “New”
- Put in a good name for your configuration, and then click Apply.
- Now, you can click Run (near the bottom). The simulator should now launch!
If that all worked, you can now move on. If it didn’t, I’d suggest Googling your problem. If you still can’t figure it out, drop me a comment on this article! I may be able to give some advice.
Step 4 — General layout
Now that everything works, it’s time to start adding placeholder items so that the general layout can be visualized, and so that testing the“required” functionality can happen sooner, rather than later.
With ConnectIQ, you can easily define per-device layouts in layout files. What are layout files? They are simply just XML files where the top level element is layout.
Technically, you can define layouts a few different ways, but again, that’s a conversation for a different day.
To see your current layout, open your project in the Project Explorer, then open the resources folder, and then the layouts folder (this is the current structure as of 8/19/2018, at least). Inside, you’ll find layout.xml
.
The current layout is fairly simple, and it should be easy to see how it matches the watch that you saw when you ran the simulator.
<layout id="WatchFace"><label id="TimeLabel" x="center" y="center" font="Gfx.FONT_LARGE" justification="Gfx.TEXT_JUSTIFY_CENTER" color="Gfx.COLOR_BLUE" /></layout>
The time itself gets set in a file under the Source
folder that ends with View.mc
.
Adding placeholders
As mentioned earlier, I have 7 pieces of functionality that I want to add. To cut to the chase, this is what the layout file looks like after those 7 additions:
Please note that I also changed the id
value of the first layout item from TimeLabel
to TimeDisplay
. I typically append Display
to all of my layout items that actually display data. You’ll have to change a line in your view file (which is present under the source
folder) if you want to follow this naming convention. If you don’t want to change anything else, change TimeDisplay
back to TimeLabel
. If you do want to make the change, find the line that looks like the following
var view = View.findDrawableById("TimeLabel");
and change it to
var view = View.findDrawableById("TimeDisplay");
If you run the simulator again, you will see something like the following:
Step 5 — Adding functionality
To turn your placeholders into items that actually display data, you’re going to need to add some functions to your View class. As always, there are many ways to add functionality, I’m choosing the “add to the View class” strategy for its simplicity. To keep this fairly long article from getting longer, I’m only going to point out a few things from the following code snippet:
- To set the value of a placeholder, you must first find it by calling
View.findDrawableById("theIdOfYourPlaceholder");
Once you have that, you can callsetText("someText")
on it. - In the snippet above, I set the scope of my functions to
private
. I highly recommend usinghidden
instead. Technically, both should work exactly the same, but I’ve ran into issues whereprivate
doesn’t work. - By separating out the setting of each placeholder into its own function, the code is “easier” to read.
- I may provide a more in-depth explanation in a future write-up.
What now?
At this point, you technically have a working watchface, and this article is taking a little longer to write than I wanted it to. As such, I’m going to summarize some of my tips/gotchyas in the next section, and save any further explanation for a different post.
Tips/Gotchyas
Prefer using `hidden` to `private`
(by the way, this was the “pitfall” I mentioned earlier…)
For scoping concerns, use hidden
instead of private
(I’ve ran into build issues when creating custom Drawables).
Come up with a naming scheme, and be consistent
This will save you tons of headaches later on when trying to find drawables by Ids, and when trying to remember what drawable means what. An example of a naming scheme is how I append Display
to the IDs of all drawables that will display data.
Stick with the default folder structure
The folder structure that is generated with the default project is great. Keep using it so that you don’t cause yourself headaches when organizing your files.
Keep in mind the differences between devices
(I said I’d mention how to handle the differences between watches earlier, didn’t I?)
Some watches support heartrate, some don’t. If you try to use it when it’s not available, your watchface will break. Garmin provides ways to check for functionality before it is used. Check out the section of Instanceof and Has on
Garmin’s developer page for more information on how to appropriately check for functionality.
Similarly, some watches only support 16 colors, while some support more than you’d ever need. Check out the chart on this Garmin developer page for more information related to supported colors.
Familiarize yourself with the documentation
The documentation, while spread out across many pages, is an invaluable source of knowledge. I’ve added some quick links to help out in your reading (I’ll probably come back to these myself!).
- The ConnectIQ framework documentation
- Announcements and main links
- The programmer’s guide. Read all of this.
- The user experience guide
Tools
As promised, here is the list of tools used for this article:
- Eclipse (the IDE that was used)
- ConnectIQ
- BMFont (not in this article, but it was used for making fonts for the colorful watchface)
- Google Chrome (to find the colors and font that Pluralsight uses)
- ScreenToGif (to make the Gifs)
- Chocolatey (in case you were interested in the setup script I mentioned)
Other links
- The source code for the colorful watch can be found here: https://github.com/JoshuaTheMiller/Multivision-Watch
- You can download the watchface itself here: https://apps.garmin.com/en-US/apps/e0a26568-1c87-44a6-99ed-2de2955dff07
End
One thing I didn’t mention at any point in this article was the fact that you can actually write tests for your MonkeyC code! This is extremely helpful when you are creating classes and functions that you may want to reuse and that you change periodically. By writing good tests, you won’t need to run the simulator every time you make a change!
Anyways, I hope this article provided some modicum of help. If anything, I hope it provided at least a decent read for a long train or bus ride!
If you’d like more information related to watchface development, let me know by clapping and commenting, I’ll see what I can do!