Handling multiple screen resolutions in efficient way

Dear Community,

I'm trying to build a power- (and, respectively, compute-) efficient Watch Face.

I have hardcoded all the possible Hands coordinates, as well as some elements positions, and store them in array, which is accessed every time the Hands are drawn. It may be an overkill, but I believe accessing an array has less power impact than calculating sinus twice (for Hours and Minutes) per minute. Also, caclulating this array in Excel was easy.

I have several (currently 2) arrays for 240 and 260 pixels screen sizes. The array is loaded on onLayout() based on the check of screen size. With this approach now, my Watch Face consumes more than 60 kB out of 91 kB memory. I'm estimating that 1 array takes about 25 kB. I can load them on onUpdate(), but that's less eficient, but still can work.

I would like to support more screen resolutions (e.g. for Venu), potentially all round-face models, but I need to find a way to load only the necessary array into the memory, and avoid keeping the unneeded onces.

Alternative approach, which will work but I don't like, is to have only one array for most common screen size (240?) and in case of other screen size do the multiplication of array elements on k, where k = actual screen resolution / 240 during onLayout()

Any ideas?

  • The cost of a sin/cos every minute is going to be pretty tiny. Of course it will be more than the cost of two array lookups in terms of cpu cycles, but it is not likely that this will be the thing that uses up battery.

    Regardless, to answer your question, it seems that you have a few options.

    1. just calculate the sin/cos values via calls to Math.sin() and Math.cos()
    2. write code that approximates sin/cos but calculates it more efficiently (not likely to be possible because the Math functions are native code)
    3. instead of storing the pre-calculated x/y screen coordinates for each of the 60 possible angles, you could store a sin/cos table for each of the angles. i.e., instead of calling Math.sin() and Math.cos() you'd just lookup the -1 to +1 values for each in the table, and then multiply and add as necessary to get the values you need
    4. instead of storing the arrays as code, use json resources, and then use the resource system to define json resource files for various screen configurations and devices. e.g., create a resources-round-390x390 folder for devices like the venu and a resources-round-260x260 for the fenix6. 
    5. continue storing the arrays in source code, but use annotations or build excludes to compile out all but the one that you need for the given target device.

    It seems to me that #4 and #5 are the closets solutions to get what you're looking for. Personally, I'd go with #4, but it sounds like the solution you want is #5.

    https://developer.garmin.com/connect-iq/reference-guides/jungle-reference/
    https://www.programmableweb.com/news/how-to-design-device-ui-garmin-connect-iq/sponsored-content/2016/10/31

  • Thanks, Travis! That's indeed the answer on my question, but now it raises 2 more:

    I actually like #4, I just don't have yet an experience with loaded resources and don't know what are their memory / CPU consumption. Is there any difference in that scope between #4 and #5?

    Also, in case I'll go with #5, can I still target multiple devices in my manifest and will I still have one application after build?

  • Is there any difference in that scope between #4 and #5?

    No. I believe the only difference is that the JSON data is loaded from a different section of the PRG file.

    can I still target multiple devices in my manifest and will I still have one application after build?

    Yes, you can still target multiple devices, but you won't have one .PRG file. If you build your application using the Export Wizard, it will compile one PRG for each part number for device in your manifest and then zip them all up into an IQ file. If you upload this to the app store, it shows up as one application that works for many devices.

  • Thanks, Travis!

    So it looks that with #5 I will have a smaller footprint on device, apart from that there is no difference.

    JSON will be more convenient to implement. but I really don't want to overwhelm the device with irrelevant data, even that it is only the storage. So, probably, will go with #5.

    Thanks again!

  • Doing the math once a minute likely has minimal impact where the actual drawing of the hands on the display probably has a larger impact on the battery, and this would be the same based on any approach.

    25k for the array is a big chunk of your memory which limits what additional things you can add to  your WF, and would be too much to run on a fr45 or Swim2 (max WF there is 48k).  If you plan to do 1hz for an analog WF with onPartialUpdate(), you'll likely use a buffered bitmap, which itself takes memory, and more so on a 280x280 device than a smaller 218x218 device (onPartialUpdate() isn't available on a venu,),

  • If you plan to do 1hz for an analog WF

    No, to be honest, I don't see that much benefit from it compared to the power consumption of re-drawing. At least in my case, where I mainly focus on astronomical data (which changes roughly once a day) and have a small gauge for steps and floors goal just to honor the main usage of the device as activity tracker by majority of the users.