Storage Access in Android 11 and above (Scoped Storage)

Sujeet Kumar Gupta
3 min readFeb 15, 2021

--

Hey there! If you are an Android Developer and wish to access Storage in Android 11 or above, the changes that need to be done in order to read/write external storage is described in this blog!

Why is this change mandatory?

Earlier after getting the storage permission, apps could access all the files on the storage (whether they required it or not) and got all the access. It was indeed a privacy breach for the users because their personal bank statements, images, or any other files that they wished to be protected, could easily be accessed by the other apps. In order to secure the files and stop the unnecessary access to the storage, they made this change compulsory for android version Q and above. Apps that run on Android 10 (API level 29) can still request the requestLegacyExternalStorage attribute. This flag allows apps to temporarily opt out of the changes associated with scoped storage, such as granting access to different directories and different types of media files. After you update your app to target Android 11, the system ignores the requestLegacyExternalStorage flag.

What is Scoped Storage?

It’s a concept of storing files, images, etc. separately by giving scoped access into external storage, or scoped storage, which restricts the conventional access of the whole storage. Better attribution: This means that the system knows which app created which file. It is useful when the app is uninstalled, all the data related to the app gets deleted and no unnecessary files are left. Thus internal app directories and external app directories are private and downloaded images, docs or any files cannot be accessed by another app.

Let's start implementation:

  1. Choosing files from external storage
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
openGallery();
} else {
allowPermissionForFile();
}
} else {
openGallery();
}

Note: In Android Q and above there isn’t a need to ask for run time permission for WRITE_EXTERNAL_STORAGE, we only need to ask for READ_EXTERNAL_STORAGE. So in manifest declare the WRITE_EXTERNAL_STORAGE permission as shown below:

<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
...
</manifest>

allowPermissionForFile()

private void allowPermissionForFile() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ActivityCompat.requestPermissions(this, new String[]
{
Manifest.permission.READ_EXTERNAL_STORAGE,
}, 2);
}else {
ActivityCompat.requestPermissions(this, new String[]
{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
}, 2);
}
}

openGallery()

private void openGalley() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Intent intent = new Intent(Intent.ACTION_PICK,MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
activity.startActivityForResult(Intent.createChooser(intent, "Select File"), IMAGE_REQUEST);
}else {
Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
activity.startActivityForResult(Intent.createChooser(intent, "Select File"), IMAGE_REQUEST);
}
} catch (Exception e) {
e.printStackTrace();
}
}

2. Capturing Image from camera

public void takePhotoForQ(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(Objects.requireNonNull(getApplicationContext()),
BuildConfig.APPLICATION_ID + ".provider", photoFile);
// Uri photoURI = FileProvider.getUriForFile(this,
// "${applicationId}.provider",
// photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, ConstantValue.CAMERA_REQUEST);
}
}
}
}

createImageFile()

String currentPhotoPath;private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = ConstantValue.IMAGE_DIRECTORY_NAME;
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);

// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = image.getAbsolutePath();
return image;
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
File file = new File(String.valueOf(currentPhotoPath));
}

Note: Don’t forget to declare FileProvider in manifest

<application>
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.android.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
...
</application>

file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Pictures" />
</paths>

Tada! That’s it! Implement these basic changes, if your app is targeting android 11. Do let me know if you have any questions or suggestions. Happy Coding!

--

--