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

Reply via email to