Search code examples
androidandroid-contentresolvermediastoreandroid-10.0content-values

MediaStore: After updating the file which is created by my app it cannot be deleted easily


Next code for deleting a file which my app owns works ok, there is no exception RecoverableSecurityException because the file was created by my app (using ContentResolver.insert(...) method)

getVideoFileContentUri(context, file)?.let { uri ->
    try {
        context.contentResolver.delete(uri, null, null)
    } catch (securityException: RecoverableSecurityException) {
        val intentSender =
            securityException.userAction.actionIntent.intentSender
        intentSender?.let {
            activity.startIntentSenderForRecsult(
                intentSender,
                REQUEST_CODE,
                null,
                0,
                0,
                0,
                null
            )
        }
    }
}

fun getVideoFileContentUri(context: Context, file: File): Uri? {
    val filePath = file.absolutePath
    val cursor = context.contentResolver.query(
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI, arrayOf(MediaStore.Video.Media._ID),
        MediaStore.Video.Media.DATA + "=? ", arrayOf(filePath), null
    )
    return if (cursor != null && cursor.moveToFirst()) {
        val id: Int = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID))
        cursor.close()
        Uri.withAppendedPath(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "" + id)
    } else {
        null
    }
}

But if I update a file created by app using ContentResolver.update(...) method then deleting the file will require permission - it throws RecoverableSecurityException and starts intent which opens a system dialog to confirm modifying the file

// here I change file name of the file
val contentValues = ContentValues(1).apply {
    put(MediaStore.Video.Media.DISPLAY_NAME, "SOME NEW FILE NAME")
}
contentResolver.update(uri, contentValues, null, null)

So now it doesn't look like my app owns that file and for deleting it my users have to confirm deletion for each file

enter image description here

This is really annoying, how can I solve this problem?

So after ContentResolver.update(...) for your own file created by ContentResolver.insert(...) app loses permission for modifying this file and will require requesting it


Solution

  • I found a solution.

    When you create a file we need to add put(MediaStore.*.Media.IS_PENDING, 1) to content values:

    val contentValues = ContentValues(5).apply {
        put(MediaStore.Video.Media.IS_PENDING, 1)
        put(MediaStore.Video.Media.DISPLAY_NAME, "INITIAL FILENAME")
        put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000)
        put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
        put(MediaStore.Video.Media.RELATIVE_PATH, relativePath)
    }
    
    val uri = resolver.insert(
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
        contentValues
    )
    

    And then when you're done with a file (e.g., finished video recording using MediaRecorder to that file) you can update it like this (you have to add put(MediaStore.*.Media.IS_PENDING, 0):

    val contentValues = ContentValues(2).apply {
        put(MediaStore.Video.Media.IS_PENDING, 0)
        put(MediaStore.Video.Media.DISPLAY_NAME, "NEW FILENAME, E.G. APPENDING END RECORDING TIMESTAMP TO PREVIOUS FILE NAME")
    }
    resolver.update(uri, contentValues, null, null)
    

    And then when calling ContentResolver.delete(...) function, requesting permission is not needed anymore (RecoverableSecurityException isn't thrown)

    try {
        resolver.delete(uri, null, null)
    } catch (securityException: RecoverableSecurityException) {
        val intentSender =
            securityException.userAction.actionIntent.intentSender
        intentSender?.let {
            activity.startIntentSenderForRecsult(
                intentSender,
                REQUEST_CODE,
                null,
                0,
                0,
                0,
                null
            )
    }
    

    Users aren't annoyed :)

    Though if a user reinstall your app, permission requesting will be required for all the files your app previously created, yeah beginning with Android Q it's not easy... :)