10

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

user25
  • 2,873
  • 2
  • 30
  • 66
  • 1
    Apps that requested all files access -like file managers will do- can delete all files using the standard File class. No need to use content resolvers or media store. No need to ask the user. – blackapps Oct 28 '20 at 22:56
  • @blackapps how do they request such access? VLC for Android also can delete easily files (it's not file manager) – user924 Oct 28 '20 at 23:03
  • https://stackoverflow.com/questions/63842070/accessing-external-storage-in-android-api-29 – blackapps Oct 28 '20 at 23:35
  • 1
    There would come batch delete for Android 11. Isnt it there already? – blackapps Oct 28 '20 at 23:52
  • "and for each file deletion it should be a different dialog, multiple deleting - no way" -- Android 11 supports batched request for access. – CommonsWare Oct 28 '20 at 23:55
  • @CommonsWare ok but I still would like to delete video files without any dialog, e.g. I need to implement "Loop recording" feature like in a dashcam device, e.g. all videos should not take more than 15 GB on the device, so when app records new videos it should delete automatically oldest one if all videos takes more than 15 GB. I could use `Context.getExternalMediaDirs` but videos are removed if app is deleted and mb other problems when different apps (like video players) would not access those videos (would not scan). But I see that VLC can delete easily file on Android 11, how do they do it? – user25 Oct 29 '20 at 08:23
  • @CommonsWare they still use 29 SDK, that's why it works for them.. Interesting if I want my video recorder app to have feature "loop recording" (which requires deleting old video files while recording, like in Dashcam devices) will it be ok to use `MANAGE_EXTERNAL_STORAGE` permission and publishing update on Google Play? – user25 Oct 29 '20 at 10:31
  • 2
    "will it be ok to use MANAGE_EXTERNAL_STORAGE permission and publishing update on Google Play?" -- I have no way of answering that. "but I still would like to delete video files without any dialog" -- you already are doing that. Your problem is that in the case where the user uninstalls your app, then reinstalls your app, that you cannot delete any old recordings from your app. IMHO, **you are overthinking an uncommon occurrence**. Just tell the user "hey, you uninstalled and reinstalled, so we need your help to clean up the old recordings", then use the Storage Access Framework. – CommonsWare Oct 29 '20 at 11:26
  • @CommonsWare ok, I agree, thanks:) – user25 Oct 29 '20 at 12:09
  • 1
    @CommonsWare it's said there is `ContentResolver#checkUriPermission(Uri, int, int)` but I cannot find this method in `ContentResolver`...https://developer.android.com/reference/android/provider/MediaStore#createDeleteRequest(android.content.ContentResolver,%20java.util.Collection%3Candroid.net.Uri%3E) – user25 Nov 21 '20 at 12:31
  • @user25: It looks like that is a bug in the documentation. There is a `checkUriPermission()` on `Context`. – CommonsWare Nov 21 '20 at 12:58

4 Answers4

4

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.

1

Well here is a good solution for Android Q and R, You can rename, duplicate or delete the file in Android R. Check this class: https://gist.github.com/fiftyonemoon/433b563f652039e32c07d1d629f913fb

hardkgosai
  • 309
  • 3
  • 5
1

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()
                )
            }
        }
    }
Rohan Arora
  • 303
  • 2
  • 12
0

There is ContentResolver.applyBatch() which will only once ask the user i think.

Have a look here:

https://developer.android.com/guide/topics/providers/content-provider-basics.html#Batch

Thomas Keller
  • 5,933
  • 6
  • 48
  • 80
blackapps
  • 8,011
  • 2
  • 11
  • 25
  • this is https://developer.android.com/reference/android/provider/MediaStore#createDeleteRequest(android.content.ContentResolver,%2520java.util.Collection%3Candroid.net.Uri%3E) – user25 Nov 21 '20 at 12:19