Strange Simulator behavior with devices < 2.0 SDK

Hi all,

I am trying to optimize one of my watch faces by avoiding complete redraw in "onUpdate". To do that I have a flag in "onShow" that is set whenever called causing the next call to "onUpdate" to redraw complete screen and then unset this flag, resulting in only changes being drawn on next call.This works fine in simulator for devices with SDK >= 2.0 but fails for devices with SDK < 2.0. For those devices I see the starting icon (blue triangle) and then slowly building up the watchface by rendering changed pixels. So my question is now whether I got something wrong in assuming that whenever a complete redraw is required, method "onShow" is called prior to that. If so, why is it not working in simulator and would it work on a real device?

Thanks!

Bye

  • Especially on older devices, you really want to redraw everything when onUpdate() is called.  There's a bunch of things you won't see in the sim.  To quote for the the early garmin folks "it's a simulator, not an emulator".

    Things like a notification may only be a toast on some devices, where the notifications only covers the top 1/4th of the screen.  You probably won't get an onShow call, as the watch face is already showing, but the top 1/4th needs to be repainted.

  • Hi Jim,

    thanks for the quick response. Does it mean that painting only changes in onUpdate is not recommended at all? For saving battery life I think it is an important thing to also spare the drawing even in onUpdate... Is it safe to say that for newer devices (SDK >= 2.3) it is safe to go with this approach or would you also say here the danger is too high to miss some drawing in case of overlays?

  • The only time I ever only update part of the screen is in onPartialUpdate.  What you can do is look at calculations vs draws.  Take for example sunrise/sunset - that's something you really only need to calculate once a day, but you can display without re-calcuating it every minute.  There are other things you can do to help with performance - such as only reading settings in initialize and in onSettingsChanged.  Otherwise, cache it.  Application.Storage is also expensive, so only read it once and save the value.

  • So my question is now whether I got something wrong in assuming that whenever a complete redraw is required, method "onShow" is called prior to that. If so, why is it not working in simulator and would it work on a real device?

    If you are implementing a watch face with partial update support, you can just overwrite parts of the screen as you see fit inside of onPartialUpdate(). When onUpdate() is called, you are expected to completely redraw the display.

    As mentioned above, the simulator doesn't perfectly capture the differences between all of the devices and the underlying graphical systems they use. We do try to avoid inconsistencies where possible, but this is one that we don't have a solution for.

  • Hi guys,

    thank you very much for your suggestions!

    I have incorporated all of them already on several optimization attempts, but wanted to even more spare battery consumption. And the logical step was to make sure "onUpdate" is also drawing only what is really required. And in general this works fine, but as you already said the Simulator is not able to simulate all the use cases. So the only information I would need is if "onShow" is always called when there is a complete or partial overlay on the screen (notification, step goal...). If so, then my logic should work, otherwise it won't.

    The general problem with my watch face is that even though I am only drawing the necessary parts (depending on the seconds this is a rectangle of 22x22, over 22x44 til 44x88) but stil the battery consumption jumps from 0.2%/hr to 0.5%/hr. I realized that there is a lot I can do by caching calculations (like Jim suggested) but I am pretty sure that I will still not be able to reach to 0.2%/hr (or even 0.3%/hr). For reference here are the timings of the Watchface Diagnostic tool:

    Total Time

    5510 (every second call)

    11621

    17731

    23842

    Execution Time:

    1956 (every second call)

    3400

    4843

    6287

    Display Time

    3536 (every second call)

    8112

    12688

    17264

    I have not found any place where I can save more time. The only thing I can consider now is to use a buffered bitmap for drawing changes in "onUpdate" and then draw that bitmap to the screen without clipping.

    In my opinion it would be really great if the API can provide an information about when there is an overlay on screen. Maybe another delegate called "onCompleteUpdate"? Simply to be able to decide whether everything needs to be updated or one can stick to the really changed pixels.

    Thanks!

  • Something else to consider is this:

    https://forums.garmin.com/developer/connect-iq/f/discussion/244331/ciq-3-2-x-devices-has-automatic-dc-clear-during-high-power-mode

    I've not verified it, but it sounds like on 3.2 devices, the screen gets cleared .

  • Hi guys,

    I have now optimized "onUpdate" so that changes are written to a buffered bitmap. I hope this will help with the battery consumption, but I would like to still request a way to know whether a complete redraw is needed or not. From my perspective the framework would know what kind of layers are currently shown and if the watchface is on top of the stack or not. Maybe a flag on the drawing context (dc) is worth to be considered?

    Thanks again!

  • Hi guys,

    I have now completed tests of the new logic inside my watchface and I am surprised how small the impact is of what I have done the last few days. Before my optimizations I had an average battery consumption of 0.5%/hr. With the standard watch face it went down to 0.2%/hr. After my optimizations that dropped the processing time significantly, I have now an average consumption of 0.4%/hr, which is not what I have expected. Almost the complete time is currently burned by drawing on dc (processing time has an average of 3000) where I cannot optimize any more. How to assure that the partial update is not dropping the battery in such a significant way? As a reference: my old Fenix 5 had an average battery consumption of < 0.3%/hr, which resulted in 14 days of lasting battery life. And this was WITHOUT the optimizations I did recently. So why is Fenix 6 behaving so different? Is it possible that there is something wrong with the firmware itself when it comes to ConnectIQ watchfaces? What other things can I do to optimize?

    Thanks!

    Bye

  • Is it possible that there is something wrong with the firmware itself when it comes to ConnectIQ watchfaces?

    It is possible.

    I think it is relevant to bring up the fact that the native watch faces are not the same as ConnectIQ watch faces. Built-in watch faces

    1. are highly optimized to minimize battery impact.
    2. are not running inside a virtual machine. Executing instructions in the ConnectIQ virtual machine is much less efficient than executing directly on the device CPU.
    3. have control over everything that is going on with the device, and can directly manage power states of things that are not exposed via ConnectIQ.
    4. are not subject to the same requirements as ConnectIQ watch faces. For example, they don't have to completely redraw the screen every second or every minute.
    5. are built into the device firmware. In some cases the code is stored different memory than a ConnectIQ watch face. This memory often has lower power requirements, and there is too little of it available to host a ConnectIQ watch face.

    Comparing two different devices is going to be difficult to do. I would not be surprised if the fenix6 and fenix5 have different capacity batteries, different memory, different amounts of memory, ... all of which would affect the battery burn rate. It is also likely they have a different virtual-machine version and small tweaks in the virtual machine can have an impact.

  • Thank you very much for your detailed explanation!

    Based on what you wrote isn't it even more important to optimize ConnectIQ watch faces so that battery consumption is minimized? I can see a lot of posts about high battery usage and I think some of those are related to ConnectIQ watch faces. "onPartialUpdate" is implemented in the best possible way (from my point of view) and there is not much we can do. But "onUpdate", forcing complete redraw, is something that can be optimized. I am not sure how much time is necessary to redraw the complete screen on Fenix 6, but when I try to do that in "onPartialUpdate" and check the Watchface Statistics, there it seems that it always shows roundabout 60 milliseconds. As this timing seems to be not exceeded, regardless of what I do (more/less calculations), it seems to be that it might take even more but is not actually shown. Considering this we have 1440*60 milliseconds which results in 86400 milliseonds (84 seconds) of calculation per day. By having the information whether the screen needs to be redrawn completely or not we can spare a lot of time that is not used for drawing operations.

    Of course I am not aware of how the logic in the firmware is build and what kind of information is available there, but as I already wrote in my previous post there must be a list that keeps track of the current view stack. And based on that it should be possible to inform in "onUpdate" whether there is a need to redraw the complete screen or not.

    Do you think this is worth consideration?

    Thanks!

    Bye