Upload Widget on Android 14 doesn't allow Camera if clientAllowedFormats: 'image'

Gobbo
Gobbo Member Posts: 8
edited June 12 in Developer APIs

I am using the Upload Widget in a normal web page (no web-view app or anything like that).
As per title, the Widget on Android 13 and older works fine.

However on Android 14, if I pass clientAllowedFormats: 'image' to exclude videos, then I do not have the usual Camera option after tapping "My files". I only get a list of images along with a message saying that "This app can only access the pictures you pick":

If I do not pass clientAllowedFormats: 'image' , then after tapping My files I do get the option of using my Camera directly, but that means I'd be able to upload videos as well, and then get denied by resourceType: 'image' after server side checks:

How do I limit the upload to images only, but also keep the possibility to take a picture directly with the camera, on Android 14?

Thank you 😊

Comments

  • Tom
    Tom Member, Cloudinary Staff Posts: 109

    Hi @Gobbo ,

    Thanks for reaching out.

    I'm able to replicate this as well and we will investigate further and keep you posted.

    Please let me know if you have any other questions in the meantime.

    Kind Regards,

    Thomas

  • Tom
    Tom Member, Cloudinary Staff Posts: 109

    Hi @Gobbo ,

    I've raised a bug for this but do not have an ETA right now but will keep you posted.

    Any other questions, please let me know.

    Kind Regards,

    Thomas

  • Gobbo
    Gobbo Member Posts: 8

    Hi @Tom ,

    thank you a lot, I will wait.

    I do have something else to ask: I was trying to find out a list of available releases and the changelog of the Upload Widget, with no luck.

    More specifically, so far I've always included something like: <script src="https://upload-widget.cloudinary.com/2.1.15/………….
    Specifying the actual version, rather than using .com/latest/…

    That was to avoid breaking changes, anyway a list of the version and a changelog would help me decide when to bump. Is that available somewhere?

    Best regards,
    Gobbo

  • Cloudinary Team
    Cloudinary Team Administrator, Cloudinary Staff Posts: 170 admin

    Hi @Gobbo,

    Thanks for getting back.

    I'm afraid there is no release log for the upload widget currently.
    One option you can do is periodically check what https://upload-widget.cloudinary.com/latest/global/all.js redirects to set your script to that version.

    Please let me know if you need anything else.

    Kind Regards,
    Thomas

    Developer Support Engineer
    Customer Success team
    Cloudinary UK


    Helpful Links For You
    💬 Share questions, connect with other users in our Cloudinary Community forums and Discord server!
    🧑‍🎓 Join our Cloudinary Academy for free courses, workshops and other educational resources.
    📄 Read our documentation for in-depth details on Cloudinary product features and capabilities
    📰 Check out the Cloudinary blog for the latest company news and insights

  • Gobbo
    Gobbo Member Posts: 8

    Hello @Tom

    Is there any update on the issue?

    Thank you

  • tia
    tia Member, Cloudinary Staff Posts: 29

    Hi there,

    It looks like the missing camera option on Android 14 is a result of the introduction of Granular Media Permissions by the Android platform.

    This is part of security hardening by Android aiming to limit access to private photos by applications. Previously, once an app got access to photos - all of them were available. Now, by default, it's up to user discretion what to share. The native Android application might request permissions to access all of the images, including camera through the granular permissions framework. In this case - the native app is the browser itself.

    The restriction applies only to images, so you may be able to work around that by not limiting the file type to images - then the restriction is not in place.

    I hope this helps. If you have any questions, do not hesitate to ask.

    Kind regards,

    Tia

  • Gobbo
    Gobbo Member Posts: 8
    edited August 14

    Hello Tia,

    Thank you for your answer.

    I might remove clientAllowedFormats: 'image' from the widget upload settings, and maintain only resourceType: 'image'.

    That would allow me to select the camera device, images and videos (that however I do not want to accept in my use case).
    Thanks to resourceType: 'image', if someone actually tries to record / select a video, the upload would go through, but eventually the resource will get rejected by the server.

    The drawback I see with this approach is that uploading videos to Cloudinary could potentially waste a lot of bandwidth quota, just to see the resource getting discarded 🤔

  • Cloudinary Team
    Cloudinary Team Administrator, Cloudinary Staff Posts: 170 admin

    Hi there,

    Could you use an eval in an upload preset? You could check for the duration of the file. If there is a duration, that means it's a video or audio file => abort the upload.
    An image would not have a duration, so it would pass the check and the upload would proceed.
    You can read about eval here:
    https://cloudinary.com/documentation/upload_parameters#events

    Let me know what you think.

    Kind regards,

    Tia
    Developer Support Engineer
    Cloudinary

    --
    💡 Improve your site's performance by applying optimization features when delivering assets


    💬 Community Forums | 🧑‍💻 Discord Server
    🧑‍🎓 Academy Training | 📖 Documentation | 📰 Blog

  • Gobbo
    Gobbo Member Posts: 8

    Could you use an eval in an upload preset? You could check for the duration of the file. If there is a duration, that means it's a video or audio file => abort the upload.

    I am trying to do so after reading the link you've posted (and also this), but I can't figure out how to "abort" the upload.

    The following code is not working, and having access to only upload_options, I don't have other ideas 🤔

    if (resource_info.duration){ return false }

  • Cloudinary Team
    Cloudinary Team Administrator, Cloudinary Staff Posts: 170 admin

    Hi there,

    Please try this for the eval

    if (resource_info.duration) { throw new Error("video files cannot be uploaded");}
    

    Let me know how it goes. Of course, if you have any questions, do not hesitate to ask.

    Kind regards,

    Tia
    Developer Support Engineer
    Cloudinary

    --
    💡 Improve your site's performance by applying optimization features when delivering assets


    💬 Community Forums | 🧑‍💻 Discord Server
    🧑‍🎓 Academy Training | 📖 Documentation | 📰 Blog

  • Gobbo
    Gobbo Member Posts: 8

    Hi Tia,

    Thank you, that is indeed working! And it is raising the exception back to the Upload widget before the rejection caused by resourceType: 'image', so initially that made me think it solves my fear of wasting bandwidth quota.

    However after checking the dev tools, it does look like it is still actually "uploading" to Cloudinary.

    I am not sure then, isn't this still impacting on bandwidth / credit usage?

    Ty

  • Cloudinary Team
    Cloudinary Team Administrator, Cloudinary Staff Posts: 170 admin

    Hi there,

    Can you share what you see in dev tools that makes you think the asset is being uploaded to Cloudinary? When I did testing on my account, I got a 400 response and the backend logs confirmed that as well.

    No storage is charged because the asset was not uploaded. And no transformations were applied, again because the asset was not uploaded.
    Bandwidth only comes into play for delivery. Only bandwidth used to deliver assets in response to requests is counted, so there's no cost implication for a failed request.

    Kind regards,

    Tia
    Developer Support Engineer
    Cloudinary

    --
    💡 Improve your site's performance by applying optimization features when delivering assets


    💬 Community Forums | 🧑‍💻 Discord Server
    🧑‍🎓 Academy Training | 📖 Documentation | 📰 Blog

  • Gobbo
    Gobbo Member Posts: 8

    Hello,

    Bandwidth only comes into play for delivery. Only bandwidth used to deliver assets in response to requests is counted, so there's no cost implication for a failed request.

    Okay, this statement alone solves the issue. It has been a while since I've read the docs and for some reason I was convinced that also the ingest bandwidth Cloudinary uses to receive assets counts.

    To clarify the rest, for posterity:

    Can you share what you see in dev tools that makes you think the asset is being uploaded to Cloudinary?

    Sure. Maybe I've expressed myself wrongly, but with "uploaded" I don't mean "saved/stored".
    I simply refer to the process of transferring the resource to Cloudinary:

    When I did testing on my account, I got a 400 response

    Same for me: I see the total byte size of the video resource being transferred to Cloudinary, and eventually getting rejected because the resource has a "duration".

    Beside the custom error message that I can set in the Error I throw in the eval, this is in my eyes the same behavior I noticed by simply having resourceType: 'image' in my Upload Widget configuration. Correct me if that's wrong.


    I voiced my concern of wasting bandwidth quota by only using resourceType: 'image', and you proposed the usage of eval in the next message. Hence the confusion… I expected something different from the usage of eval (e.g. the user doesn't need to wait for the transfer completion), but from what I see it's basically the same. POST req and 400 res:

    • Only having resourceType: 'image'
    • After adding the expression in the upload preset eval field:

    If my assumption is correct, I think I will nonetheless keep the eval because I like the possibility to return a customized error message.

    Thanks

  • Cloudinary Team
    Cloudinary Team Administrator, Cloudinary Staff Posts: 170 admin

    Hi there,

    My apologies. I misunderstood your message when I replied suggesting eval
    Your assumption is correct 😊

    Kind regards,

    Tia
    Developer Support Engineer
    Cloudinary

    --
    💡 Improve your site's performance by applying optimization features when delivering assets


    💬 Community Forums | 🧑‍💻 Discord Server
    🧑‍🎓 Academy Training | 📖 Documentation | 📰 Blog

  • Gobbo
    Gobbo Member Posts: 8

    Hi,

    No worries and thank you for your support!