Android 6.0 - external storage files being deleted upon app uninstall
Asked Answered
A

1

13

My app uses the DownloadManager to download files to a subdirectory of the device's Music folder.

DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
...
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) + "/MyStuff/song.mp3");
request.setDestinationUri(Uri.fromFile(file));

I have noticed that the files are being deleted when the app is uninstalled from a device running Marshmallow (this is not happening on older OS versions). Do you have any ideas about this?

Thanks

Avert answered 4/2, 2016 at 18:59 Comment(7)
I can reproduce this behavior. I'm not terribly shocked that they did this, but that does feel like a regression.Uriisa
Note that the same behavior occurs with Android 5.1 (tested on a Nexus 4), but does not with Android 4.1 (tested on a Galaxy Nexus), so the change happened in that range. It's not strictly new to Android 6.0. Based on emulator testing, it looks like the change came in Android 5.0 -- 4.4 keeps the download, 5.0 does not.Uriisa
Does this only happen for downloaded files, or for all files placed in one of the public folders by an app? If only for downloaded files, then a quick copy would alleviate this, yes?Ordeal
@Ordeal it's only for downloaded file. But I wonder if it's also done for files put there with addCompletedDownload().Rock
@Ordeal it seems to be happening only for downloaded files. I have implemented a file copy as a workaround for this bug: note that the copied file needs to have a different file name, a swap won't work.Avert
@MatteoInnocenti, thank you. This is good to know.Ordeal
Any updates on this?Marguerita
R
5

This is done by an internal class called DownloadReceiver and defined in the com.android.providers.downloads package manifest

<receiver android:name=".DownloadReceiver" android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        <action android:name="android.intent.action.UID_REMOVED" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_MOUNTED" />
        <data android:scheme="file" />
    </intent-filter>
</receiver>

Here the android.intent.action.UID_REMOVED action catches the eye. It was introduced in Lollipop triggering a call to handleUidRemoved() performing

resolver.delete(ALL_DOWNLOADS_CONTENT_URI, Constants.UID + "=" + uid, null);
Rock answered 7/2, 2016 at 18:10 Comment(6)
This intent seems to be referring to a user (UID) removed, not an application, (which it would make sense to remove user's downloads after their user is deleted.) developer.android.com/reference/android/content/…Kinglet
@Kinglet It's not connected to a real user. It refers to Linux system user id assigned to the application. developer.android.com/guide/components/fundamentals.htmlRock
I see. My mistake.Kinglet
Great find! Nice job.Minestrone
@Rock Any way to prevent this activity? I'd like the files, downloaded through the app, stay in the external memory of the device even if the app is uninstalled.Outhaul
@Outhaul I don't know if there's any official fix for this feature. What i've been doing is, downloading the file with another name and change the file name on android.intent.action.DOWNLOAD_COMPLETE bcast receiver. it actually keeps the file but some what sounds like a hack. If you get any other solution, please let me know.Fountain

© 2022 - 2024 — McMap. All rights reserved.