How can a watchface display an image downloaded in the background by makeImageRequest?

The subject really says it all. I'm successfully downloading an image using makeImageRequest in a background process. I believe the image is stored in the graphics pool, and the background process has a reference to it as a Graphics.BitmapReference.

How then can I access this image from the main watchface view?  I can't used Background.exit() to return the BitmapReference since it isn't one of the allowed types for exit(). It should be obvious how to do this, but I can't see how.

Thanks in advance for any help.

Michael

  • I've got makeImageRequest working with CIQ 5.02 on an Epix 2, and with SDK 7.4.3 on the simulator with code compiled with minimum supported API level 5.0.0 - System 7. This is in the background from a watchface.

  • I saw it working for the Epix 2 also, but not on any other CIQ 5 device I tested. To be fair I didn't test every CIQ device in the simulator, but the ones that I did test all gave the same error. This tracked with other threads here in the forum that it was an issue with background not having access to graphics pool memory. The fix doesn't address the background to graphics pool access issue, rather it reverts to CIQ 3.x behavior. It's a little strange that this is the only CIQ 5.0 device that got the fix, but at least we know there is a fix and that it may find it's way to the rest of the CIQ 5 devices.

  • To access the image from the foreground, you need to use Application.Storage.setValue(data) to store the BitmapReference in the background, and you can then access it in the foreground with Application.Storage.getValue.

  • I'm not sure how to make "makeImageRequest" works in the background now in 5.1 when it didn't in 5.0 any more clear.

    By simply posting the code that you are trying to use or describing it clearly enough so that others know wtf you are talking about. Since your first post in this thread, you haven't bothered to clarify specifically what bug you are talking about.

    Hint: "makeImageRequest doesn't work in the background" isn't enough information for us, especially since we have confirmed that indeed there is a way for makeImageRequest to work in the background for both CIQ 3 devices and CIQ 4+ devices, which suggests that you are doing something different.

    It would also be helpful to be more precise with your language. The issue under discussion is not about makeImageRequest itself failing in the background, it's about the apparent inability to pass the image returned by makeImageRequest to the foreground.

    If makeImageRequest itself is indeed failing for you then:

    - you could've clarified that earlier (use your words!)

    - it's a different issue than what OP is talking about (reading is fundamental)

    Sounds like you yourself have never tried to use makeImageRequest in the background on a watchface with a CIQ 4 (now CIQ 5.0) device, or you would know

    It sounds like you didn't bother read this thread or the comment you just replied to. Like this is the #1 source of ridiculous disagreements on these forums and the internet at large: people come out with guns blazing while failing to read or understand the thing that they're replying to. It doesn't help that people often continuously double-down to the point of absurdity, when challenged with any kind of argument that contradicts the position they're stubbornly clinging to.

    Nobody has code with makeImageRequest that works for CIQ 4.0 through CIQ 5.0.

    Are you sure about that?

    If you have makeImageRequest code working in the background of a watchface of your own we would all love to see it.

    I literally posted:

    - a link to working code in the comment you just replied to

    - a link to a bug report with working code in this comment (the bug report is related to a type check error)

    - a description of working code in this comment, confirmed by 1148788 here

    Among those posts, I said that I tested my solution in the simulator (venu2s, ciq 5.0.0) and on a real device (fr955, ciq 5.0.2), with a small proof of concept example. I didn't bother to post the full code of my proof of concept, since 1148788's issue had been resolved, but I posted a working code snippet in the related bug report, and I described it pretty adequately, I think.

    I did manage to get this working on a simulated venu2s (CIQ 5.0.0), by:

    - calling Application.Storage.setValue() on the received data (without modification) in the makeImageRequest callback, in the background process

    - calling getValue() in the foreground process and passing the return value (without modification) to dc.drawBitmap

    I'll try on a real fr955 (CIQ 5.0.2) at some point and get back to you.

    EDIT: yeah it also works on a real fr955.

    I'll clean up my code and post a working example later, but there isn't much more to it than what I said above.

    One thing I noticed is that while the code definitely works, it does produce a typecheck warning at level 2 (error at level 3) for the Storage.setValue() line, because as previously discussed, setValue() is not defined as taking a BitmapReference for the 2nd argument. I think it's worth filing a bug report over this.

    EDIT: I won't bother posting the code since the issue is resolved.

    Furthermore, other comments in this thread have described things which do *not* work:

    - calling get() on the returned bitmap reference in the background

    - using instanceof BitmapReference in the background

    - Using Background.exit() to return the bitmap reference

  • Nobody has code with makeImageRequest that works for CIQ 4.0 through CIQ 5.0

    Furthermore, this thread also contains discussion of a watchface in the CIQ store, Daily Flower by VAW.BE, which apparently pulls down images from the internet using makeImageRequest in the background, and supports CIQ 4+ devices.

    The developer of that watchface posted a comment in the thread implying that they indeed use makeImageRequest in the background.

    TLDR; but it seems you guys already got it working. It was a struggle to get this system working, but glad it's all good now! Have a great one! 

    Idk how much evidence you need tho. You could simply try the described solution on a CIQ 4.x/5.0.x watch (real or simulated).

    I saw it working for the Epix 2 also, but not on any other CIQ 5 device I tested
    It's a little strange that this is the only CIQ 5.0 device that got the fix, but at least we know there is a fix and that it may find it's way to the rest of the CIQ 5 devices.

    Except Daily Flowers (also by VAW.BE) supports multiple CIQ 4/5.0 devices and has been in the store since July 2024, implying:

    - makeImageRequest in the background has worked since at least July 2024, at least the way VAW.BE is doing it (I assume it's the same as what we've described above)

    - it's not just epix gen 2 that works

    Maybe your specific approach has been recently fixed, but I guess we'll never know since you won't describe it or show us your code. (Seems that you're trying to access the graphics pool / graphics module based on some of your comments, which we can all agree isn't allowed in the background.)
  • Can indeed confirm that it just works on all these devices (System 6 and newer). Fenix 7+, Venu2+, Fr255+, Vivoactive 5,... I just use the makeImageRequest in the background and save the result in the storage. No type checking here. 

  • public function requestWebImg() as Void {
    	Communications.makeImageRequest(_url, _params, _wPic, method(:onReceiveWebImg));
    }
    	
    Error: Exception occurred
    Details: failed inside handle_image_callback
    Exception: Class usage is not allowed for the current app type.

    The code is really simple. The callback method never gets called, I get the class not allowed error. I have a println as the first line in the callback function and it doesn't print. If yours work as you say, what options have you set in your third parameter?

  •         var imageWidth = screenSize * 0.75;
            var imageHeight = screenSize * 0.75;
            
            var options = {
              :maxWidth => imageWidth,
              :maxHeight => imageHeight,
              :dithering => Communications.IMAGE_DITHERING_FLOYD_STEINBERG,
              :packingFormat => Communications.PACKING_FORMAT_JPG,
            };
    
            Communications.makeImageRequest(url, null, options, method(:responseImage));

  • The code is really simple.

    public function requestWebImg() as Void {
        Communications.makeImageRequest(_url, _params, _wPic, method(:onReceiveWebImg));
    }
    what options have you set in your third parameter?

    Imagine asking for details about other people's code that you won't provide for your own.

    You say your code to reproduce the problem is "really simple" (while omitting the details of your 3rd argument, which implies that it isn't important), but then you ask someone else for their 3rd argument (implying that the 3rd argument is actually significant). So maybe it's not so simple after all.

    Why don't you provide *your* 3rd argument (and possibly your url, or an example of an image that you are trying to download) so that we could try recreate your problem and/or so that we know to avoid the specific situation you are running into?

    Here's mine, from the bug report I mentioned:

    Communications.makeImageRequest(
        "https://services.garmin.com/appsLibraryExternalServices/api/icons/a41f0afd-4802-4406-a8d0-d47336e5d988",
        null,
        {},
        method(:onReceiveImage)
    );

    Also, if you had read the OP and most of the replies to this thread, you would realize that OP is actually successfully calling makeImageRequest in the background, and the actual problem they had was passing the image to the foreground - i.e. a completely different problem than the one you are describing.

    So either there is a problem with the specific image(s) you are trying to download, and/or the specific options you are using.

    Ofc this could've been abundantly clear from the start, if only you would've expanded on your original super-vague statement that you refused to clarify until now.

    "This only works for CIQ 3.x devices. Garmin made a breaking change to the way graphics were handled starting with CIQ 4 and now it is no longer possible."

    Note that the use of the word "this" in that quote is highly misleading, because again, you and OP are talking about two different problems.

    To recap, this is what OP said:

    I'm successfully downloading an image using makeImageRequest in a background process. I believe the image is stored in the graphics pool, and the background process has a reference to it as a Graphics.BitmapReference.

    How then can I access this image from the main watchface view?  I can't used Background.exit() to return the BitmapReference since it isn't one of the allowed types for exit(). It should be obvious how to do this, but I can't see how.

    That's where it would be helpful to:

    - read and understand things you are replying to

    - clarify exactly what you are talking about when you say something doesn't work

  • I think I found the problem. Once again it's with the Garmin back end servers. It seems to work only for static images, I convert it to png so I can get transparency for a round image and return it through php but then nginx sends it back to Garmin with Transfer-encoding: chunked. This works for a browser, but Garmin can't handle it apparently.