breautek commented on PR #889: URL: https://github.com/apache/cordova-plugin-camera/pull/889#issuecomment-2233226006
> This plugin is using ACTION_GET_CONTENT intent, so this new photo picker is actually used under the hood. So I modified this plugin Ok this is good... I thought we were using some other intent and didn't actually realise `ACTION_GET_CONTENT` will actually use the photo picker. Android docs doesn't explicitly state this but if we restrict the media type (which in most cases we do) then android will choose the best picker/application for the requested type of content. The bad news is, simply using the picker and removing the permissions isn't the complete solution. Bear with me this will be quite a lengthy post... but this will explain the situation. To be clear, this is not the fault of this PR or anything, just things that Cordova has done in the past because it seemed like a good idea at the time and never has updated or introduced the breaking changes required to move to newer concepts and now Cordova is getting a bite of those consequences. First, I've done all my testing using the `FILE_URI` mode, and only using images. I'm assuming videos has identical behaviour. Cordova takes primarily two different paths when using the camera API: 1. Sourcing new content from the camera hardware 2. Sourcing existing content from the gallery Sourcing new content from the camera does work, regardless of permissions or API level. This works because the native receives a `content://` uses the content resolver and reads the content and writes it to an app-specific cache directory and then returns the app-specific [internal](https://developer.android.com/training/data-storage#categories-locations) `file://` path, which is usable by the filesystem APIs. While this works... it is kinda problematic for a reason I'll get into later. Sourcing existing content from the gallery however doesn't do file copy. It instead simply resolves the content:// to the [external](https://developer.android.com/training/data-storage#categories-locations) file system path and returns that. Both READ_EXTERNAL_STORAGE and READ_MEDIA_* permission requirements comes from the fact that the API shares these external URIs. They are required if you use the Filesystem APIs instead of the MediaStore APIs. In API 30, Android has a concept of FUSE filesystem that maps external FS kernel calls to the media store to enforce access but this does not grant the application temporary access that the content:// urls does when using the media store. Scope storage exists in API 29 which also lacks this FUSE filesystem so I believe this is currently completely broken on API 29 devices. #### Solution 1 > While this works... it is kinda problematic for a reason I'll get into later. So the quick solution which will fix API 29, and should also allow us to eliminate the storage permissions is to do what we do when sourcing content from the camera. Use the content resolver to obtain the content and write it to app-specific cache and return those uris instead of external paths. This isn't a breaking change, we aren't changing the public API. But the reason why this approach is problematic is, copying large files obviously will take time. So picking videos will likely not give a good user experience, depending on the size of the video. Image content is usually manageable in terms of file size. Here are some code references: - https://github.com/apache/cordova-plugin-camera/blob/master/src/android/CameraLauncher.java#L576 (if you follow the method calls, it will eventually return a temporary file location to write to) - https://github.com/apache/cordova-plugin-camera/blob/master/src/android/CameraLauncher.java#L583 (here, if you follow into the method, we use the content resolver to get the content output stream) and copy via a 4096 byte buffer to the temporary cache location - https://github.com/apache/cordova-plugin-camera/blob/master/src/android/CameraLauncher.java#L586 (here, we return the tempoary file location uri back to the webview) The problematic returns are likely: - https://github.com/apache/cordova-plugin-camera/blob/master/src/android/CameraLauncher.java#L574 (which I think returns the uri from gallery if it already exists in the gallery, probably yielding an external or content URI) - https://github.com/apache/cordova-plugin-camera/blob/master/src/android/CameraLauncher.java#L733 (which is the main handler method for processing the result from gallery) #### Other Thoughts I've also explored passing content:// uris directly to the webview, which poses several issues: 1. The webview will not accept `content://` uris (despite even using `setAllowContent(true)` on the webview settings). Android docs doesn't state anything on why this might be the case but blocking content uris might be intentional based since Android KitKat on https://issuetracker.google.com/issues/36985138 (aka when Android moves to a chromium based webview). 2. Apache Cordova doesn't have a media store interface, so the user can't programmatically interact with the content 3. content:// uris give temporary access to the app, which makes the uris not persistent. Once the app activity closes, access to the content:// content is expired. So if the user wants to persistently access that resource, they **must** be able to programmatically interact/copy the data making issue 2 a big deal. cordova-android platform could solve the first issue by mapping a path inside the [WebViewAssetLoader](https://developer.android.com/reference/androidx/webkit/WebViewAssetLoader) that can resolve to the content:// uri and make use of the content resolver and return that content. But the other 2 issues will be prevalent without a media store API. There are third-party plugins available for a media store API but I don't think Apache Cordova should build the core plugins to rely on third-party plugins. Being able to use content:// uris (even indirectly) is probably much better, but will require a lot of other moving parts to occur first. Additionally, requiring the use of a media store plugin for android also isn't ideal when iOS will need to continue to use the file plugin APIs. Cordova code is meant to be shared across platform, so we can't have a plugin API that requires using the result in two different ways depending on the platform. Therefore Cordova ideally needs to figure out how it can incorporate content:// uris in the file plugin APIs so that usage can be consistent cross platform. #### Final Thoughts Due to time constraints, I don't think the content:// solution is viable, so I think we are stuck with the first Solution. I know this is a lot, I'm not sure if this is still something you are willing to work on. If not, then that's okay too, we can probably still make use of what you've done in this PR and implement the rest in another PR. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: issues-unsubscr...@cordova.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: issues-unsubscr...@cordova.apache.org For additional commands, e-mail: issues-h...@cordova.apache.org