When woken, 'onUpdate' is called 6 times before `onExitSleep` called

Hello friends,

Does anyone else have a watch face that makes it obvious when a low-power mode paint has happened?  It seems that onUpdate() is getting called more often that it should during low-power mode during the wake-up sequence, and I want to know if this is specific to my faces or general across Connect IQ. 

If a watch face wouldn't change what's displayed between these paints, it would be hard to notice this.  But my faces have some features that can make this more visible (described below).

I started looking into this because a few of my customers have been complaining about a lagginess when the watch face swaps from low-power mode to high-power mode.  I can reproduce this on my devices (including an Epix Gen 2 Pro 51mm), but this behavior isn't replicated in the simulator on any device.

On various AMOLED devices, when I wake the screen via a tap or the light button, onUpdate() gets called ~6 times (in immediate succession) before onExitSleep() is called.  Because of this, the watch face is getting painted 6 extra times in the "low power mode" display before the "high power mode" display is painted.  As a result, the watch appears to lag when switching from low power mode to high power mode, because it continues for a second or so in the low-power mode before finally switching.

I would expect that upon a wake event (such as a screen tap or pressing the "light" button), the next call would be onExitSleep() and then onUpdate().  We would generally want the watch to immediately wake up and show the high-power mode. 

To be clear:

  • I do not use animations or anything that would be expected to trigger this behavior (nor should they work in low-power mode)
  • There is no code that's running WatchUi.requestUpdate();

In general, one major limitation Garmin enforces is that in low-power mode developers cannot use timers or otherwise refresh the screen more than once per minute.  So this suggests that it's unlikely I've written code that is causing this.

I have reviewed other posts in the forums and not found anything related.  This was the closest post I found:

onUpdate is called twice
This post doesn't seem to involve the sleep/wake events.

The docs aren't exactly precise about what to expect, but they do say this:

When a gesture occurs while running in low power mode the system will call onExitSleep() to notify the application that the transition to high power mode has occurred.

The only thing I can see in the docs that may suggest what I'm seeing is somehow expected is this bullet under the onUpdate() method:

More than one call to onUpdate() may occur during View transitions

But I understand this to apply more to if a view gets pushed with an animation like SLIDE_X.  No such thing is happening here that would suggest this is a view transition.

I have thought about building some kind of workaround to prevent rapid low-power mode repaints, but before I do that, I wanted to ask the community if this could be reproduced by others before reporting it as a formal bug.

This is particularly obvious on my faces, because I've built my faces with an internal burn-in protection system that moves each low-power mode paint up to 6px from the center.  In addition, my watch faces include an advanced option to paint the draw time in milliseconds for each paint.  As a result, you can clearly see the individual paints happening in low-power mode before the wake, since the red numbers update rapidly and the whole face moves with each paint.

Here's a video showing this behavior.  Watch the red numbers on the left.  Every time that updates corresponds to a new call to onUpdate().  

Click here to play this video

If you can't view the directly-embedded video above, try this link: www.dropbox.com/.../IMG_3610-copys.mov

It is fully possible that this is happening to other developers but not getting noticed, since you'd have to be able to see some variation per-paint.  Otherwise, it'll just be repainting the same thing, which wouldn't be noticeable.  But it would be causing lagginess and wasting some battery.

Some other details:

  • The watch face in this video is: LUXE Relux Daytona (RLX)
  • My device is running 15.77 (I'm part of the beta program, but this doesn't appear to be a beta issue)

I've also noticed a hard-to-replicate issue where the low-power mode actually gets stuck triggering updates once per second.  This is especially obvious on my faces, because each paint in low-power mode moves the entire face slightly to reduce the chances of burn-in.  I'll make a separate post about that, since it seems to be a separate issue.

Top Replies

All Replies

  • Yes, I reported this on another forum.  On the Epix and other AMOLED watches of the same family (Fenix7), onUpdate is called way too many times.   Oddly, on a Venu 3, the number onupdate calls is considerable less.  

    On may watch faces, this difference is noticeable when raising the wrist to view the face.  The Epix is less responsive than the Venu 3.  Which I think Garmin should find a bit embaressing given the Epix is the higher end model.

  • Same problem. Epix gen2 a lot more lagging than my Venu 2 Plus

  • I just wanted to bump this conversation back to the top of the forums: has anyone discovered a fix for this?

    I implemented a solution that detects "unneeded paints" by checking if anything of (clock time, power mode) has changed since the last one.  If a paint request comes in with the same clock time and power mode as last time, it skips the paint by returning early and not painting the screen.

    On Epix 2, this works well.  The "no paint" just leaves the prior image on screen.

    But now Fenix 8 customers are reporting that the screen "flickers black" between state updates.  I don't have a Fenix 8 to test on, but I assume it's because the Fenix 8 is handling this differently.  When my code "skips a paint," it sounds like the Fenix 8 is blacking the screen out.

    Does anyone have more context?

  • I gave Garmin a watch face that counts the number of excessive calls to onUpdate and video showing the lag compared to a Venu 3

    fingers crossed that they fix this embarrassing performance issue on their top of the line watches!

  • Can you show your solution for the epix? 
    would be interested to fix this somehow, even though fenix8 is not covered.

  • My actual code is really particular to my own architecture, using variables and things I've set up to make my life easier.  But I approached this problem from the following principle:

    The extraneous paints happen when the onUpdate() call is made, despite the power-mode (low/high) not changing and the clock second not changing.  Therefore, just take note of the timestamp and power mode of the last paint and, when a new update request comes in, decide if there's anything different.

    But now I'm finding that the devices behave differently from another in an undocumented way.  Some devices black out the screen at the start of an update, so if you don't draw anything, the user sees a black screen.  Other devices leave the prior screen intact.

    Has anyone found a pattern to this?  Is it more common that the screen gets blacked out between onUpdate calls?  Or is it more common that the view is retained?

  • Has anyone found a pattern to this?  Is it more common that the screen gets blacked out between onUpdate calls?  Or is it more common that the view is retained?

    This can vary by device and you won't see it in the sim.  On some devices, the dc is cleared before onUpdate is called, and on some it isn't.

    Basic rule is whenever onUpdate is called, you want to draw everything on the screen.  You can't just do a field or two.

    See this bug report and the posts from Travis:

    forums.garmin.com/.../vivoactive-4-clears-screen-before-onupdate

  • Thanks.  The performance impact is so serious, though, as to make it seem worthwhile for me to identify which device conforms to which policy and branch the logic accordingly.

    On Epix 2 Pro, my "bogus onUpdate detection & rejection system" is the only thing standing between users and the silly 1x/second onUpdated() calls happening in LOW power mode.  That's right.  This bug has been going on for over a year.  

    That's right: in LOW power AOD mode, the firmware is requesting updates every single second.  It's maddening.

  • The performance impact is so serious, though, as to make it seem worthwhile for me to identify which device conforms to which policy and branch the logic accordingly.

    According to jim_m_58, there is zero performance or battery life to be gained by only drawing part of the screen during onUpdate(), bc the firmware will refresh the whole screen in onUpdate() anyway (for watchfaces). That’s right, the code that actually runs in onUpdate() doesn’t matter, it only matters what pixels the firmware decides to refresh.

    (This is not referring to the bug where onUpdate() incorrectly runs all the time tho.)

    When I asked him to elaborate on his logic and respond to some objections, he suggested that I go develop a watchface and find out for myself.

    https://forums.garmin.com/developer/connect-iq/f/discussion/383881/persistence-of-the-dc-content-between-calls-to-onupdate/1829656#1829656

    Even if you change only one line in onUpdate, the battery impact is the same as the entire screen is redrawn by the FW, unlike with onPartialUpdate where only part is redrawn..
  • What's the performance bottleneck? If it's some computation that you do in onUpdate then maybe it can be moved outside of the function or you can also draw to a buffer, and in case you detect this beheaviour then use the buffered bitmap from the previous call to onUpdate to draw to the screen instead of redrawing it.