CameraView
CameraView copied to clipboard
Android 10(SDK Version 29) Shared Storage rules adaptation (Uri oriented)
Problem (inconvenience)
New Android shared storage concept dictates a set of new rules for media files access. Developers have to leave Java File API approach and start work with files through content provider. In order to create a video file using CameraView on SDK 29 and higher I have to:
1. Create and publish new video item to MediaStore collection using ContentResolver and mark that item with MediaStore.Video.Media.IS_PENDING flag(so this item will be unavailable until this flag present).
val videoCollection = MediaStore.Video.Media
.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val videoDetails = ContentValues().apply {
put(MediaStore.Video.Media.DISPLAY_NAME, name)
put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
put(MediaStore.Video.Media.IS_PENDING, 1)
}
val uri: Uri = resolver.insert(videoCollection, videoDetails)
2. Get FileDescriptor with item Uri using ContentResolver and save it somewhere (viewModel for example) for later.
val videoFileDescriptor = resolver.openFileDescriptor(uri, "w", null)?.fileDescriptor
3. Start video recording by putting videoFileDescriptor to cameraView.takeVideo(fileDescriptor: FileDescriptor) function.
4. After video captured in CameraListener onVideoTaken(result: VideoResult) function inactivate MediaStore.Video.Media.IS_PENDING flag to make video available using that "saved for later" video Uri.
val fileDetails = ContentValues().apply {
put(MediaStore.Video.Media.IS_PENDING, 0)
}
resolver.update(uri, fileDetails, null, null)
5. We are done. Happy end.
So, I just described the process of video creation using new Android 10 Shared Storage rules approach and CameraView. Remember that we do not have to use Java File API, so FileDescriptor is the only way to record a video.
If you look on described flow, you can easily notice that we have one inconvenience - we have to generate FileDescriptor with Uri and store that Uri somewhere to use it later for making video available(MediaStore.Video.Media.IS_PENDING flag).
Solution
It would be much easier for developers to have a function like cameraView.takeVideo(uri: Uri), so step 2 (resolving FileDescriptor from Uri) can be done by CameraView directly. AND to make the solution complete, add uri: Uri parameter to VideoResult class.
So a developer creates media item using ContentResolver.insert() function and gets Uri of that item, then provides it to new cameraView.takeVideo(uri: Uri) function and when video capture is finished use that Uri (just from VideoResult in onVideoTaken(result: VideoResult) listener function) in ContentResolver.update() function.
As a result there is no need to store Uri somewhere, we provide it to CameraView and then get it back in listener.
The same is for "take photo" use case.
Thanks for the clear description! The proposed solution sounds good to me. Would you like to work on it?
@yaroslavkulinich or @natario1, any update about this issue? Will URI support be added in the future?
So what's the right way to use this for VideoSnapshot with Android 10+ and the new file system?
We need to be able to take videos with images overlayed and the takeVideoSnapshopt functions don't have an option to use a FileDescriptor as the parameter.
I would like to know how I can help implement this solution?
You can store it in cache directory then export that video using MediaStore API, or you can take persistable permission of specific folder and save video into that folder directly.
You can store it in cache directory then export that video using MediaStore API, or you can take persistable permission of specific folder and save video into that folder directly.
I was able to add @yaroslavkulinich's solution to the project. I created a pull request, but I am not sure if it went through.