Archive

Monthly Archives: January 2014

After being inspired by a post on Reddit, I made a watch face that imitates the ‘time /t‘ and ‘date /t‘ commands in the Windows Command Prompt. This was the result:

mockupSince then, I had a brilliant idea to improve it using AppTimers and show it as a user would type it, every minute.

The result is CMD Time Typed, and looks like this:

mockupThat’s a lot better. The source is available on GitHub, and the package is available from MyPebbleFaces. Enjoy!

 

Advertisements

It’s been a long time since the last release that had any major changes, but after much work the re-write is now complete, and released to Google Play!

The main change is the new UI, which has a much better flow and use of Android APIs, such as ActionBar Tabs. Here’s the spot-the-difference…

wt compare

That old design had been the same almost since it was first published to the store!

The watchapp for the Pebble has also changed for SDK 2.0 users, but this was already released a couple of versions ago. It looks like this:

watchapp

The other main changes are thus:

  • Overhauled Android app UI for better navigation.
  • Added portrait photo shooting orientation.
  • Added vibration during countdown option.
  • Added FAQs in Settings.
  • An inaccessible path is now automatically reset.
  • Fixed setting flash preference from watch bug.

Hopefully the update will be worth the time, and bug free! ALthough it has been known for me to release apps with bugs that only appear on different device configurations than my own, or through unusual use cases. Fingers crossed!

Get the apps here:

Watch Trigger               

Get it on Google Play

Watch Trigger +

Get it on Google Play

Required Reading

Pebble SDK 2.0 Tutorial #1: Your First Watchapp

Pebble SDK 2.0 Tutorial #2: Telling the Time

Pebble SDK 2.0 Tutorial #3: Images and Fonts

Pebble SDK 2.0 Tutorial #4: Animations and Timers

Introduction

In this section of the tutorial we will be returning back to basics, building a simple watchapp that will use button presses (or clicks) and vibrations to enable the user to give input and receive output.

To get started, make a new CloudPebble project and add the C file from section 1, which consists of just the basic app life-cycle functions and a TextLayer. Since it is so brief, here it is again in full (with a couple of refinements for clarity):

#include <pebble.h>

Window* window;
TextLayer *text_layer;

/* Load all Window sub-elements */
void window_load(Window *window)
{
	text_layer = text_layer_create(GRect(0, 0, 144, 168));
	text_layer_set_background_color(text_layer, GColorClear);
	text_layer_set_text_color(text_layer, GColorBlack);

	layer_add_child(window_get_root_layer(window), (Layer*) text_layer);
	text_layer_set_text(text_layer, "My first watchapp!");
}

/* Un-load all Window sub-elements */
void window_unload(Window *window)
{
	text_layer_destroy(text_layer);
}

/* Initialize the main app elements */
void init()
{
	window = window_create();
	WindowHandlers handlers = {
		.load = window_load,
		.unload = window_unload
	};
	window_set_window_handlers(window, (WindowHandlers) handlers);
	window_stack_push(window, true);
}

/* De-initialize the main app elements */
void deinit()
{
	window_destroy(window);
}

/* Main app lifecycle */
int main(void)
{
	init();
	app_event_loop();
	deinit();
}

Now you’re back up to speed, it’s time to add the first new element: button clicks. The way this works in the Pebble SDK is that you provide the system with callbacks for what you want to happen when the button is pressed, just like with a TickTimerService implementation. These callbacks have the following signatures:

void up_click_handler(ClickRecognizerRef recognizer, void *context)
{

}

void down_click_handler(ClickRecognizerRef recognizer, void *context)
{

}

void select_click_handler(ClickRecognizerRef recognizer, void *context)
{

}

These will be needed in init() so make sure to place them above that function in the source file. To keep areas of code separate, place them above the window_load() and counterpart function to keep all Window related functions in one place in the file.

We will leave these blank for now as we continue to put all the pieces in place required for button click functionality. The next step is to register these with the system so it knows what to do when the button clicks occur. This is done in another function called a ClickConfigProvider, which (you guessed it) provides the click configuration. It looks like this, when filled with the requisite function calls necessary to register the individual button press callbacks from earlier. Each call links a button to its callback. Hopefully you can read it easily:

void click_config_provider(void *context)
{
	window_single_click_subscribe(BUTTON_ID_UP, up_click_handler);
	window_single_click_subscribe(BUTTON_ID_DOWN, down_click_handler);
	window_single_click_subscribe(BUTTON_ID_SELECT, select_click_handler);
}

After creating the button callbacks and providing a mechanism for telling the system what each individual button will do when pressed, the final step is to provide the system with the click_config_provider() function to enable it to call it and set up the button click behaviors. The back button cannot be controlled by the developer as it is used to back out a watchapp to the system menu! This final step is achieved in init() after the Window is created (but before it is pushed!) like so:

window_set_click_config_provider(window, click_config_provider);
window_stack_push(window, true);

Now we have our button clicks registered, let’s make them do something! Perhaps the simplest and easiest demonstration is to have the buttons change the text being shown by the TextLayer. First, change the prompt shown to the user in window_load() from “My first watchapp!” to something a bit more relevant, such as “Press a button!”. Now, in each button click handler callback function, add another text_layer_set_text() function call to set the text shown to that particular button. Here is just one example (do the other two yourself in a similar fashion!):

void up_click_handler(ClickRecognizerRef recognizer, void *context)
{
	text_layer_set_text(text_layer, "You pressed UP!");
}

After adding some actions to the three callbacks, compile the watchapp (make sure it is actually a watchapp as dictated by ‘App kind’ in the Settings screen) and test it. It should look like this:

pressed

So, there you have button clicks. To change the behavior, just change what happens in the callback functions. The rest can stay the same.

Vibrations
With buttons providing a means of user input to your app, the next main means of output, besides what is being displayed on the screen, is to use the built-in vibration motor to notify users to events. For example, in my Pebble Tube Status app (another shameless plug!) the watch vibrates once the updates data has been sent to the watch, so in the case of a slow data connection, the user can ignore the watch until the information is ready for viewing.

To use this functionality is much simpler than anything else we’ve covered so far. You can make the watch vibrate simply with one single line:

vibes_short_pulse();

/* or */

vibes_long_pulse();

/* or */

vibes_double_pulse();

To initiate a more complex vibration sequence, use a different form as shown below (I placed this in up_click_handler(), for example):

//Create an array of ON-OFF-ON etc durations in milliseconds
uint32_t segments[] = {100, 200, 500};

//Create a VibePattern structure with the segments and length of the pattern as fields
VibePattern pattern = {
	.durations = segments,
	.num_segments = ARRAY_LENGTH(segments),
};

//Trigger the custom pattern to be executed
vibes_enqueue_custom_pattern(pattern);

Conclusion
That’s pretty much all there is to button clicks and vibrations, which wraps up this part of the tutorial.

You can find a link to the full source code resulting from what we’ve covered here on GitHub.

Next up: an introduction to working with PebbleJS and AppMessage. Basic knowledge of JavaScript required!

After a couple of weeks work, I have almost finished a huge overhaul to Watch Trigger. It’s been stripped down, redesigned and rebuilt. A lot of things have changed, and a lot of things have been improved!

Screenshot_2014-01-07-00-54-14

However, at the current count, there are over 7000 active users, and after my fair share of scares releasing buggy software to this many people, I’ve learned that a good amount of testing is in order. But some bugs only come up on devices other than my own, so I’m appealing for testers who want to take the plunge early and report back what they find.

If you are one of these people, Tweet me or E-mail me and let me know!

Isn’t this exciting? If only my VHDL design wasn’t so hard I’d be enjoying that this evening.

Known bugs:

  • With Instant Review off, the reset button still appears.
  • Instinctively pressing back from Settings exits Activity.

Back to work! This means I’ll be developing stuff in my spare time rather than all day. I know, it’s sad news.

Things to expect eventually (in the weeks range):

  • More Pebble SDK 2.0 Tutorial sections. A list of planned ones can be seen here.
  • A new UI for Watch Trigger &+ that better resembles Holo, but with that distinctive red theme. I’m also working on portrait shooting, but the Camera API hates me. It works, but the layout always seems to make the Preview View stretched and distorted. Here’s a sneak preview:

Screenshot_2014-01-05-00-10-50

  • Toying with ideas for a ‘canned’ SMS responses app that can be customised on the phone, then set to the watchapp. We’ll see.

Hopefully Watch Trigger on the Play Store is stable enough to fend for itself for the time being. If not, let me know.