In the first article we saw the changes in file access throughout the evolution of Android and the changes implemented in Android 10 by Scoped Storage, which was created to improve user privacy and control of the information stored by applications, as it limits access to sensitive user information by applications that should not have access to it and also ensures the automatic deletion of all data created by the application when it is uninstalled.
The following shows how a developer should adapt their applications.
If an Android application targets Android 10, storage changes by scope are already active. However, while it is not mandatory to support storage by scope on Android 10, it will be a requirement for Android 11.
If the developer of the application wants to wait for Android 11 to implement file access changes and maintain the current behavior, just activate the legacy mode, which can be activated by placing android:requestLegacyExternalStorage=”true” in the Application Manifest file.
Access to files that do not need to be shared with other applications
Even without enabling legacy mode, if an application only creates files for data storage that do not need to be shared with other applications, such as media or downloads, no changes are required in its deployment. The files created by the application will be stored in a virtual file system that will be transparent to the application.
However, applications that used to access data that aren’t from the user and are not media files, will no longer be able to access them. Access to generic files will only be possible through the SAF (Storage Access Framework), a library for accessing Androids storage. For more details on using SAF.
Understanding the place of storage
In the implementation of storage by scope we have the concept of volume, which indicates which device (main memory or memory card) the files should be read from or written to. For main memory, a constant has been created to indicate this storage location, which is MediaStore.VOLUME_EXTERNAL_PRIMARY.
However, for the memory card, we need to call MediaStore.getExternalVolumeNames to get a list of all available volumes:
How to create new media files or Downloads
When using Scoped Storage, it is not necessary to request any permission from the user to write files to either the main memory or the memory card. Access is done using the MediaStore content provider, so it is necessary to request the creation of the new file and then have write access to it. For more details on how the MediaStore works, you can read here.
Creation of a new archive:
As we saw above, we have passed the name of the new file, your mime type and we turn on flag IS_PENDING. This flag is used to notify the content provider that the file is not yet complete. In this case, when any application lists the files available through the MediaStore, the files with this flag active will not be listed.
As a result, the variable item contains the URI of the new file, which will be used to open it for writing and recording:
When we finish the changes to the file, we change the flag IS_PENDING indicating that the file is complete and we have updated the MediaStore:
Listing the files
Not many changes were made to list media files using Scoped Storage. You must make a query in the MediaStore requesting the desired files in the same way that it was possible in previous versions of Android:
A major change implemented from Android 10 was the introduction of the file owner concept. The owner is the name of the package the application that created this file. As the files now have an owner application, when a query is made on MediaStore, only the files created by application itself are listed. However, on devices that have been upgraded to Android 10, previously created files do not have an owner, and are no longer listed.
To list your media files created before a system upgrade or even media files created by other applications, you must request READ_EXTERNAL_STORAGE permission. When this permission is granted, all media files (audio, video, images) are listed and released for reading.
An important detail is that, although it is possible to write files to the Downloads folder using storage by scope, it is not possible to read or list the files using the content provider. To access these files, you must use SAF.
Reading in files
Once we have the URI of the file we want to open – which can be obtained through a query on MediaStore as shown above – we can open the file for reading. Remember that files in which your application does not own or files generated in previous versions of Android can only be read with the permission of READ_EXTERNAL_STORAGE.
Renaming and deleting files
As the access to the media files is done by the MediaStore, to rename or delete files, just make the change in the content provider and the changes are reflected in the file system.
To delete a file:
To rename a file:
However, for both cases, these operations are allowed only in files that have been created by application itself. Accessing a media file from other applications or own files created on an old Android version generates the RecoverableSecurityException exception.
When this happens it is still possible to execute the operation, but we need to ask permission for the user to complete the operation. To do this, we need to handle this exception and request permission:
After the user confirms or denies access to this file, the answer is obtained in the onActivityResult method:
The changes made to Android 10 for storage by scope have brought privacy improvements for the user and guaranteed deletion of files created when they are uninstalled. Scoped storage also offered developers a unique solution for accessing main storage and memory card.
However, again, there was a big change in the APIs, forcing developers to adapt their applications to Android 10 and maintain different implementations for each version of the operating system to maintain backward compatibility.