androidvideo-capturescoped-storage

Video Capture intent in Android 30+ - Only owner is able to interact with pending item


I am trying to capture video on my app. It works below android API 30 but does not work on 30+. Seems like after sdk 30, android does not allow to read external storage entirely (scoped storage). I am currently having this error:

java.lang.IllegalStateException: Only owner is able to interact with pending item content://media/external_primary/video/media/57

Now I have three questions:

  1. How can I create video capture intent that saves video to apps internal storage? (Because scoped storage limitations are for external storage)
  2. I can get content uri at onActivityResult, how to make this uri accessible and readable? (After I read this file, I will create a temporary file with it and edit this temp file.)
  3. What is the proper way to capture a video with scoped storage limitations?

video capture intent

private fun dispatchTakeVideoIntent() {
    Intent(MediaStore.ACTION_VIDEO_CAPTURE).also { takeVideoIntent ->
        takeVideoIntent.resolveActivity(packageManager)?.also {
            startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE)
        }
    }
}

onActivityResult

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    if (resultCode == RESULT_OK){

        when(requestCode){
            
            REQUEST_VIDEO_CAPTURE -> {
                val videoUri: Uri? = data?.data
                setVideo(videoUri)
            }
        }
    }
}

videoUri looks like this: content://media/external_primary/video/media/57

setVideo function normally gets the content uri, creates a temporary file from it, compresses, and gets a thumbnail from this file. And then I upload this file to the server.


Solution

  • Thanks to @CommonsWare s advice, I created a file with File provider and supply uri of this file with EXTRA_OUTPUT. Now I am able to do stuff with videoUriForAddingCaptureVideo and videoPathForAddingCaptureVideo variables. I am posting this answer to give a clue to fellow developers.

     private fun dispatchTakeVideoIntent() {
    
        val videosFolder = File(
            Environment
                .getExternalStorageDirectory(), application.applicationContext.resources
                .getString(R.string.app_name)
        )
    
        try {
            if (!videosFolder.exists()) {
                val isCreated: Boolean = videosFolder.mkdirs()
                if (!isCreated) {
                    Log.e(TAG,"dispatchTakeVideoIntent : storage error")
                    return
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    
        val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
        val videoFileName = "VID_" + timeStamp + "_"
        val storageDir: File? = application.applicationContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
    
    
        try {
            val video = File.createTempFile(
                videoFileName,  /* prefix */
                ".mp4",  /* suffix */
                storageDir /* directory */
            )
            videoUriForAddingCaptureVideo = FileProvider.getUriForFile(application.applicationContext, application.applicationContext.packageName + ".provider", video)
            videoPathForAddingCaptureVideo = video.absolutePath //Store this path as globe variable
    
            Intent(MediaStore.ACTION_VIDEO_CAPTURE).also { takeVideoIntent ->
                takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, videoUriForAddingCaptureVideo)
                takeVideoIntent.resolveActivity(packageManager)?.also {
                    startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE)
                }
            }
    
        } catch (e: ActivityNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    
    
    }