Pebble: Android Companion Case Study
- Tutorial

And so, how to use PebbleKit Android to integrate Pebble and an Android application using the notification of the number of missed calls as an example : a bit of code, translation of excerpts from the documentation [1] and very few pictures.
The thesis is how the interaction of the mobile application and watchappp works:
- Companion application recognizes, connects and exchanges information with Pebble through the PebbleKit library;
- watchapp (watchface) and the mobile application exchange messages in a two-way mode, the channel is identified on both sides by the UUID of the Pebble application;
- the exchange between the Pebble application and the mobile application is carried out by Dictionary objects [2] .
To solve the problem, display a notification on the watch about the number of missed calls, you must:
- Pebble-application that can receive, process and display information from a companion application;
- An Android application that tracks calls and sends the number of unanswered to our application on the watch.
Watchapp
In the Pebble application, just like in the case with PebbleKit JS, the AppMessage API mechanism is used [3] .
Since our application itself does not initiate a communication session, but only waits for a message from the smartphone, I will use the Synchronizing App UI [4] - an auxiliary layer on top of AppMessage, which simplifies the synchronization of values between watchapp and a mobile device. Only two callbacks are used, one in the case when the predefined value is changed, and the other if the error occurs.
We define the key, AppSync and the buffer for synchronizing the tuple:
#define KEY_CALLS_COUNT 41
static AppSync s_sync;
static uint8_t s_sync_buffer[32];
We initialize the synchronization mechanism and the initial value of the tuple in a separate function:
/* ... */
static void start_sync() {
app_message_open(app_message_inbox_size_maximum(),
app_message_outbox_size_maximum());
// Начальная инициализация кортежа (0 неотвеченных)
Tuplet initial_values[] = {
TupletInteger(KEY_CALLS_COUNT, 0),
};
app_sync_init(&s_sync, s_sync_buffer, sizeof(s_sync_buffer),
initial_values, ARRAY_LENGTH(initial_values),
sync_changed_handler, sync_error_handler, NULL);
}
static void init(void) {
/* ... */
start_sync();
}
Defining callbacks:
/* ... */
static char s_count_buffer[4];
/* ... */
static void sync_changed_handler(const uint32_t key, const Tuple *new_tuple,
const Tuple *old_tuple, void *context) {
// Преобразовываем полученное значение в строку
snprintf(s_count_buffer, sizeof(s_count_buffer),
"%d", (int)new_tuple->value->int32);
// Помечаем слой с индикатором для перерисовки
layer_mark_dirty(layer);
}
static void sync_error_handler(DictionaryResult dict_error,
AppMessageResult app_message_error,
void *context) {
APP_LOG(APP_LOG_LEVEL_ERROR, "sync error!");
}
/* ... */
NB In this case, the key used to exchange the value does not require registration in appinfo.json.
If we run our simple application now, then there will be a lone indicator on the screen (0 missed calls):

Android app
You can get the number of missed calls in Android in different ways, in this example I will take it from the “curtain” with notifications - Notification Area.
The application itself consists of two classes: MainActivity for entering the UUID of the watchapp, which will receive data, and the NotificationListener service, which tracks notifications.
NB Access to the Notification Area through the NotificationListenerService appeared in Android 4.3. Since the additional metadata Notification.extras is used, the example will be guaranteed to work only on Android 4.4+.
For Android Studio, adding PebbleKit is done through a gradle file.
Add to app / build.gradle :
dependencies {
compile 'com.getpebble:pebblekit:2.6.0'
}
repositories {
mavenCentral()
maven { url "https://oss.sonatype.org/content/groups/public/" }
}
After synchronization, PebbleKit can be used in your project.
To access notifications, I use the NotificationListener class inherited from NotificationListenerService with overridden methods onNotificationPosted () and onNotificationRemoved ():
public class NotificationListener extends
NotificationListenerService {
@Override
public void onNotificationPosted(
StatusBarNotification sbn) {
this.getMissedCalls();
}
@Override
public void onNotificationRemoved(
StatusBarNotification sbn) {
this.getMissedCalls();
}
}
When adding or removing notifications, all active ones are scanned and if there is information about missed calls, their number is sent to the application on the watch:
public class NotificationListener extends
NotificationListenerService {
// Счетчик пропущенных вызовов
int missedCallsCount = 0;
/*...*/
void getMissedCalls() {
int tCount = 0;
for (StatusBarNotification notif :
this.getActiveNotifications()) {
if (notif.getPackageName().equals("com.android.phone")) {
String extras_text = notif.getNotification().extras.getString(Notification.EXTRA_TEXT);
if (extras_text.indexOf("Пропущенных вызовов:") != -1) {
tCount = Integer.parseInt(extras_text.split(":")[1].trim());
}
}
}
if (tCount != missedCallsCount) {
missedCallsCount = tCount;
this.sendMissedCalls(missedCallsCount);
}
}
}
To send data to the watch, we determine the key, UUID, form the dictionary and use the sendDataToPebble method:
public class NotificationListener extends
NotificationListenerService {
UUID APPS_UUID;
private static final int CALLS_KEY = 41;
/*...*/
public void sendMissedCalls(int missedCalls) {
APPS_UUID = UUID.fromString(this.getUUID());
PebbleDictionary data = new PebbleDictionary();
data.addUint32(CALLS_KEY, missedCalls);
PebbleKit.sendDataToPebble(getApplicationContext(), APPS_UUID, data);
}
/*...*/
}
To give the application access rights to notifications, you need to add to the manifest:
Note, after installing the application, it is necessary to enable the service, it will not work without authorization. The setting is located on the path “Settings” -> “Security” -> “Notification access”. In the Russian locale, I have "Settings" -> "Privacy" -> "Access to notifications."

We launch the android application, specify the UUID of the Pebble application in it, call and do not answer, see how the notification on the watch changes:

Sources:
notice watchapp - pbw
PebbleNotify (Android Studio project) - apk
1. Pebble Developers // Mobile App Developer Guide
2. Pebble Developers // Dictionary
3. Pebble Developers // App Communication
4. Pebble Developers // Synchronizing App UI