Solved: Issue with Pebble framebuffer after notification is dismissed

Effect Layer Issue I’ve encountered a weird issue while working with EffectLayer Library (a visual effect library for Pebble smartwatch). In this particular watchface called Clean & Smart I used “invert” effect which inverts colors of the watchface should the user choose that option in settings. It was working fine when option changed when watchface was loaded/unload and behaved weirdly only in one particular scenario: when you would receive a notification (email, text etc.) and then dismiss it. Upon coming back from notification to watchface invert effect would only partially cover the watchface (as seen on the screenshot).
I don’t know exactly what was happening, but had a theory. EffectLayer uses Pebble’s framebuffer capabilities – which gives you direct memory access to screen. In this particular case “invert” effect would loop thru every byte of that memory inverting values, causing related pixels on screen to invert colors. Now, when you dismiss a notification it disappears with sliding animation effect. So when watchface reappears and EffectLayer begins to kick in – not entire screen is available for manipulation, hence only partial invert effect.

With this theory in mind I decided to utilize Pebble Pebble AppFocusService API. It provides events and handlers that allow you to detect various stages of your application losing and gaining focus.

First we need to subscribe to focus events, we can do this in init part of app code:

app_focus_service_subscribe_handlers((AppFocusHandlers){
  .did_focus = app_focus_changed,
  .will_focus = app_focus_changing
});

This snippet subscribes to 4 events: when application about to lose focus (.will_focus with boolean false passed to the handler), about to gain focus (.will_focus with boolean true passed to the handler), lost focus (.did_focus with boolean false passed to the handler), got focus (.did_focus with boolean true passed to the handler).

Now we need to add handlers. First we need to catch moment when notification is being dismissed and watchface is about to gain focus:

static void app_focus_changing(bool focusing) {
  if (focusing) {
     layer_set_hidden(window_layer, true);  
  }
}

What this does – if focusing event is detected – code hides root window layer. If we leave it at that – when notification is dismissed – original screen is restored, but it will remain static, it won’t reflect any events including time change. So we need to add this:

static void app_focus_changed(bool focused) {
  if (focused) {
     layer_set_hidden(window_layer, false);  
     layer_mark_dirty(window_layer);
  }
}

issue_fixed what this does – is when focus is finally restored – code restores root window layer visibility and refreshes it. And the result you can see in the screenshot – invert effect is covering entire screen.

4 replies on “Solved: Issue with Pebble framebuffer after notification is dismissed”

  1. I’ve had the same notification related problem on some of my watchfaces on the PTR.
    It’s a Pebble fault, which has been always been there (a number of us suffered it at PDR15).
    It doesn’t just occur when manipulating framebuffer. I’ve had it on faces with images and a recent one where I just draw arcs. I’ve applied your fix to one of each and it works there too.
    Great stuff. Thanks.

  2. Excellent, I’ll have to give this a try. A few of my faces suffer from this issue and it’s a pain to even try to debug since I can’t replicate it in the emulator.

    Great stuff and thanks!

  3. @MicroByte – they *might have* resolved it in latest firmware updates, so this might not be needed anymore, but it doesn’t hurt to check and perhaps keep this approach as a safeguard.

Leave a Reply

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