How can I delete file on Android 11 (API 30) without system confirmation dialog?

Viewed 13451

I have an app which records videos to shared MOVIES folder.

I can delete those files on Android 11 (API 30) with contentResolver.delete(uri, null, null) method in my recorded videos activity.

But if I reinstall the app then it looses permissions to those files... (so afwul) and in such case I need to do something like this:

try {
    context.contentResolver.delete(uri, null, null)
} catch (exception: Exception) {
    if (exception is RecoverableSecurityException) {
        val intentSender = exception.userAction.actionIntent.intentSender
        intentSender?.let {
            callback?.startIntentSenderForResult(
                intentSender,
                requestCode
            )
        }
    }
}

So it couldn't delete the file using ContentResolver because app was reinstalled and there is exception which we can catch and open the next annoying dialog for a user to confirm deletion (and for each file deletion it should be a different dialog, multiple deleting - no way)

enter image description here

Then I installed Explorer app from Google Play on this Android 11 device (emulator), when I opened it the app only asked for storage write permission (my app also does it) and this Explorer app could easily delete any file (including my record videos files) without any confirmation dialog.

So how do they do it? Is it a hack or what is that?

Link to the app https://play.google.com/store/apps/details?id=com.speedsoftware.explorer

Update

VLC for Android can also delete any media file https://play.google.com/store/apps/details?id=org.videolan.vlc

They also use content provider, so it's the same but it returns true unlike my app, why?

fun deleteFile(file: File): Boolean {
    var deleted: Boolean
    //Delete from Android Medialib, for consistency with device MTP storing and other apps listing content:// media
    if (file.isDirectory) {
        deleted = true
        for (child in file.listFiles()) deleted = deleted and deleteFile(child)
        if (deleted) deleted = deleted and file.delete()
    } else {
        val cr = AppContextProvider.appContext.contentResolver
        try {
            deleted = cr.delete(MediaStore.Files.getContentUri("external"),
                    MediaStore.Files.FileColumns.DATA + "=?", arrayOf(file.path)) > 0
        } catch (ignored: IllegalArgumentException) {
            deleted = false
        } catch (ignored: SecurityException) {
            deleted = false
        }
        // Can happen on some devices...
        if (file.exists()) deleted = deleted or file.delete()
    }
    return deleted
}

https://github.com/videolan/vlc-android/blob/master/application/vlc-android/src/org/videolan/vlc/util/FileUtils.kt#L240

4 Answers

Android 11 (API 30) without system confirmation dialog you can do but you need to manage_external_storage permission. The permission is allowed to some specific category application.

  • File managers
  • Backup and restore apps
  • Anti-virus apps
  • Document management apps
  • On-device file search
  • Disk and file encryption
  • Device-to-device data migration

Manage all files on a storage device

If your app do not follow the above category so you do not allow to publish with manage_external_storage permission.

If your application is a gallery, video, and audio player so you do not need to manage_external_storage permission and you can delete it directly with the system confirmation dialog.
Here you can get the example to delete media file

Before android 11 you can direct the used file.delete() method and delete your file.

In the android 11 file.delete() method only works if you create your own content. for example, Your application download one image and the location is external storage in this casework file.delete() method.

if you want to delete media files like camera or screenshot that time file.delete() method not work in android 11 because the media content you are not created. This situation follows with a system confirmation dialog.

below is a code snippet that works for all android versions till Android 11

fun deleteFile(path_of_file :String){

        val uri = Uri.parse(path_of_file)

        try{
            // android 28 and below
            contentResolver.delete(uri, null, null)
        }catch (e : SecurityException){
            // android 29 (Andriod 10) 
            val intentSender = when {
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {
                    MediaStore.createDeleteRequest(contentResolver, listOf(uri)).intentSender
                }
                // android 30 (Andriod 11) 
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
                    val recoverableSecurityException = e as? RecoverableSecurityException
                    recoverableSecurityException?.userAction?.actionIntent?.intentSender
                }
                else -> null
            }
            intentSender?.let { sender ->
                intentSenderLauncher.launch(
                    IntentSenderRequest.Builder(sender).build()
                )
            }
        }
    }
Related