Public file storage on Android 10

Alessandro Mautone
3 min readFeb 5, 2020

Before Android 10

In the past in order to save content, let’s say an image, on a device from our app and make it publicly available to all the apps installed on that device we could just do:

or, since we are talking about a media file in this case, we could do the following(which should be more of a robust solution):

Those 2 implementations, together with WRITE_EXTERNAL_STORAGE permissions, work until Android 9, while they throw a SecurityException on Android 10.

Since Android 10

On Android 10 things slightly changed: we can still save content in external media directories, but only through the content resolver.
Here is an example of how to do it:

In this new implementation we can see a couple of new content values:

  • RELATIVE_PATH ->Can be used to specify a subfolder in the directory of destination e.g. if we are saving into the pictures directory and we want our content to be saved into Our_subdirectory we can just pass ${DIRECTORY_PICTURES}/Our_subdirectory as in the example shown above.
  • IS_PENDING -> Used to tell the content resolver there is an operation going on. Once we copied the data in the destination file (done in the copyFileData() function), we can set this value to false like shown at the end of the example above.

Copying the data into the destination file can be easily done in the following way:

I used the File Descriptor in this example, but it can be done also using the output stream.

What about different types of content?

We made examples assuming we wanted to save an image file, what about other types of files?
The MediaStore class contains different subclasses for this purpose:

In the previous examples, you could see we were using MediaStore.Images.xyz , so those are the available ones:

MediaStore.Images
MediaStore.Video
MediaStore.Audio
MediaStore.Downloads

As a general rule, I tend to save all the media content in the related subtype folder (so a .mp3 file will use the MediaStore.Audio class) while everything else goes in the downloads folder using the MediaStore.Downloads class.

Notes

Unfortunately, the APIs used in Android 10 are not available in the older versions of Android, which means we need to maintain two different ways of saving content externally, which is not ideal.

In the Android 10 example, we said we add content through the content resolver, and we do so using content values. We can see that we use the VOLUME_EXTERNAL_PRIMARY to get the relative collection uri in which we are going to store our file information.
This value is available only on Android 10, and the Android official documentation states we could use VOLUME_EXTERNAL on older APIs, which will definitely make our lives easier as well as improving our code by not having two completely different implementations to achieve the same result on different Android versions.
Unfortunately, when I tried to use the VOLUME_EXTERNAL the compiler was showing an error saying it is only available on Android 10 😅

--

--

Alessandro Mautone

Android Lead Engineer @Canyon 🤖 🇻🇪🇮🇹 Paraglider, Runner, Kayaker.