Scoped Storage — Android
Final (Part-3)
Overview
In the final article of this android storage & file storage series we will be learning about the scoped storage benefits. In order to have basic knowledge about the file storage in android, I would recommend you to go through Part 1 and Part 2 of this series. Scoped storage was introduced in android 10 and the developers were given choice to opt out this feature until they make changes to support this feature in their app. But starting from android 11 it is compulsory that your app works with scoped storage.
Key Features
- Unrestricted access for an app to access its own internal and external storage without any storage permissions.
- No storage permissions are required if you want write your app specific media files to the media collections. However read permission is need to query all the files including the app specific files and the files created by other apps.
- Organizing files as a collection that are specific to a particular app only.
- Protecting the app related data like files from the other app since they are stored in the scoped storage.
- When the user uninstall the app, all the files that are specific to that particular app is also removed.
Note: Apps that are storing its files in the shared storage should start moving all the files that are more specific to it to the app directories in order to retains those files in the future.
Here is the snippet that saves file to the media store. No storage permission are required from Android 10 onwards.
fun saveFileToMediaStore() {
// specify path and image attributes
val values = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "paris")
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
put(MediaStore.Images.Media.IS_PENDING, 1)
}
// specify storage where file has to created
val imageUri =
appContext.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
// read a image file from assets and writing to a file we created above
val assetManager = appContext.assets
val inputStream: InputStream
var bitmap: Bitmap? = null
try {
inputStream = assetManager.open(SAMPLE_FILE_NAME)
bitmap = BitmapFactory.decodeStream(inputStream)
} catch (e: Exception) {
Timber.e(e)
}
appContext.contentResolver.openOutputStream(imageUri!!).use { out ->
bitmap!!.compress(Bitmap.CompressFormat.JPEG, 90, out)
}
values.clear()
values.put(MediaStore.Images.Media.IS_PENDING, 0)
appContext.contentResolver.update(imageUri, values, null, null)
}
}
Note: Read permission request is required to query even for the app specific files because the system considers the file to be attributed to the previously-installed version of the app, rather than the newly-installed one.
Here IS_PENDING values were update from 1 to 0 because when it is set 1, it denotes that particular file is undergoing write or some operation and it can’t be listed in the images collection when queried. Once it is set to 0, it is available to all.
After running this operation, you can cross check whether the image is saved in the Pictures directory or not using File Manager Application.