Reputation: 2644
I am using the android app and trying to add the gallery videos to my video editing screen. But it failed to show the video and showing a black screen.
Can any one let me know what I am doing wrong.
I am click on the gallery icon and try to open the video from the ACTION_PICK and send that video to the next Activity.
Problem: I am getting this error in LogCat:
java.lang.SecurityException:
UID 10170 does not have permission to content:
//com.google.android.apps.photos.contentprovider/-1/2/content%3A%2F%2Fmedia%2Fexternal%2Fvideo%2Fmedia%2F25/ORIGINAL/NONE/video%2Fmp4/1574077794
[user 0] at android.os.Parcel.createExceptionOrNull
Here is my code:
VideoFragment.kt
R.id.imageViewVideo -> {
if (android.os.Build.VERSION.SDK_INT >= 32) {
val intent = Intent(Intent.ACTION_PICK, null) // It shows the videos alone
intent.type = "video/*"
resultLauncher.launch(intent)
} else {
requestPermission()
}
}
private val resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
val data: Intent? = result.data
val videoUri: Uri = data?.data!!
Log.i("videoUri", videoUri.toString()) // content://com.google.android.apps.photos.contentprovider/-1/2/content%3A%2F%2Fmedia%2Fexternal%2Fvideo%2Fmedia%2F1000000024/ORIGINAL/NONE/video%2Fmp4/1940625115
val videoPath = parsePath(videoUri)
if (videoPath != null) {
Log.i("videoPath", videoPath)
/storage/emulated/0/Movies/VID_20231115_163657.mp4
Log.i("videoPath22", videoUri.path.toString()) /-1/2/content://media/external/video/media/1000000024/ORIGINAL/NONE/video/mp4/1940625115
}
val intent = Intent([email protected](), SelectVideoActivity::class.java)
intent.putExtra("path", videoPath)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent)
}
}
Next Activity File: (SelectVideoActivity.kt)
onCreate()
val source = File(intent!!.getStringExtra("path")!!)
copyFile(source, inputFile)
Log.i("input file ===", inputFile.toString())
@Throws(IOException::class)
fun copyFile(sourceFile: File?, destFile: File) {
try {
if (!destFile.parentFile!!.exists()) destFile.parentFile!!.mkdirs()
if (!destFile.exists()) {
destFile.createNewFile()
}
var source: FileChannel? = null
var destination: FileChannel? = null
source = FileInputStream(sourceFile).channel
destination = FileOutputStream(destFile).channel
destination.transferFrom(source, 0, source.size())
}
catch (e:Exception){
Log.i("error","selectvideo ${e.message}")
}finally {
// source?.close()
// destination?.close()
initViews()
setListener()
}
}
For the lowest version of Androids the path looks like below and it works fine
Filepath:
/storage/emulated/0/DCIM/Camera/VID_20231121_193407.mp4 /storage/emulated/0/Android/data/com.app.packagename/files/app-name/1700718359149.mp4
Code:
private lateinit var inputFile: File
onCreate method:
inputFile =
File(getExternalFilesDir("slow-mow")!!.absolutePath.plus("/" + "${System.currentTimeMillis()}.mp4"))
Upvotes: 2
Views: 525
Reputation: 2644
It got worked with the below ACTION_OPEN_DOCUMENT and saved the file in cache and used the path
R.id.imageViewVideo -> {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT, null)
intent.type = "video/*"
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
data?.data?.also { uri ->
//Permission needed if you want to retain access even after reboot
requireContext().contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
val path = copyInCacheDir(uri)
Log.e("file path", "onActivityResult: path ${path.toString()} ")
val intent = Intent(requireActivity(), com.example.exoplayerslowmotion.SelectVideoActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
intent.putExtra("path", path.toString())
startActivity(intent)
requireActivity().finish()
}
}}
private fun copyInCacheDir(videoUri: Uri): String? {
try {
val contentResolver = requireContext().contentResolver
if (videoUri.authority == "com.google.android.apps.photos.contentprovider") {
contentResolver.takePersistableUriPermission(
videoUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
}
val returnCursor = contentResolver.query(videoUri, null, null, null, null)
returnCursor?.use { cursor ->
if (cursor.moveToFirst()) {
val displayNameIndex = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
val sizeIndex = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)
val displayName = cursor.getString(displayNameIndex)
val size = cursor.getLong(sizeIndex)
val inputStream = contentResolver.openInputStream(videoUri)
val cacheDir = requireContext().cacheDir
val outputFile = File(cacheDir, displayName)
val outputStream = FileOutputStream(outputFile)
val bufferSize = 1024
val buffer = ByteArray(bufferSize)
var bytesRead: Int
while (inputStream?.read(buffer, 0, bufferSize).also { bytesRead = it!! } != -1) {
outputStream.write(buffer, 0, bytesRead)
}
inputStream?.close()
outputStream.close()
Log.d("Video Copy", "Video copied to: ${outputFile.absolutePath}")
return outputFile.absolutePath
}
}
} catch (ex: Exception) {
Log.e("Video Copy Error", "Error copying video: ${ex.message}", ex)
}
return null
}
Upvotes: 0
Reputation: 765
There is no problem with action pick video, it works fine and retured data.
You dont need path
of source video, that cause the security problem, just use uri
and read it with ContentResolver
.
// copy file
val uri = intent.getData()
contentResolver.openFileInputStream(uri)?.use { inStream ->
val destFile = // you dest file, prefer to use context.getExternalFilesDir
destFile.outputStream().use { os ->
inStream.copyTo(os)
}
}
Noted
Android/data/package-name/...
) to copy file, save edited fil, then you can scan the file to Gallery if you need.Upvotes: 0
Reputation: 1007296
Replace:
val intent = Intent(requireActivity(), SelectVideoActivity::class.java)
intent.putExtra("path", videoUri.path)
startActivity(intent)
with:
val intent = Intent(requireActivity(), SelectVideoActivity::class.java)
intent.setData(videoUri).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(intent)
And, in SelectVideoActivity
, use getData()
on the Intent
to retrieve the Uri
.
See this blog post of mine for more.
Even better would be to only have one activity and use fragments or composables for separate screens.
Upvotes: 2