I have been reading the documentation of the new way of saving files in android 11 and it is not clear to me ...
How could I save a file in /storage/emulated/0/?
My code only works on android 9 or lower (android 10 if I use preserveLegacyExternalStorage property in manifest, but on android 11 it doesn't work)
Android 11 introduces new approach to accessing storage, called Scoped Storage. Now for storing in any path you need new permission for Android 11: MANAGE_EXTERNAL_STORAGE (doc HERE, some rich FAQ aritcle in HERE)
This will allow you to get access to whole storage, all subfolders, not only folder dedicated for your app, but be aware that not every app with this permission declared in manifest will be published in Google Play. So you should respect new policy and keep your files only in context.getExternalFilesDir("subdirName"), for reading some common types (images, videos, docs) you can still use MediaStore API
Related
I want to find an updated answer that works from android 5/6/7 to 13 with less possible permission. I know there are answers like Android saving file to external storage storage but those are very old.
You can understand accessing and storing files on android better from the google's official documentation here, mainly app-specific storage vs permission requirement, i.e. if you want to save file which are app specific, you won't need permission whether it being internal or external storage, but if you want to access locations which are not your app-specific, you will need permission for both internal and external storage.
Also, this behavior of permission requirement has been adopted after a particular API level, so you can start writing you code as per your targetSdk version and keep including options down to your minSdk versions and have a common method for permission for reusing it wherever is required.
The behaviour changes for Android 13 mention this:
If your app targets Android 13, you must request one or more new
permissions instead of the READ_EXTERNAL_STORAGE and
WRITE_EXTERNAL_STORAGE permissions.
(https://developer.android.com/about/versions/13/behavior-changes-13#granular-media-permissions)
The new permissions are:
Images and photos: READ_MEDIA_IMAGES
Videos: READ_MEDIA_VIDEO Audio
Audio files: READ_MEDIA_AUDIO
But how to handle this, if I e.g. need to read PDF files from an arbitrary folder? There's no permission like READ_MEDIA_DOCUMENT or something like that. What about other file types, which are not images, videos or audio? Can I still use READ_EXTERNAL_STORAGE permission for them?
I didn't find any information about this in the official documentation, but to be honest the documentation is focusing on media files only without any word about other file types (https://developer.android.com/about/versions/13/behavior-changes-13#granular-media-permissions).
I am also not sure about WRITE_EXTERNAL_STORAGE permission for other document types beside of videos, images and audio.
According to documentation (https://developer.android.com/training/data-storage/shared/media#storage-permission):
No permissions needed if you only access your own media files
On devices that run Android 10 or higher, you don't need any storage-related permissions to access and modify media files that your app owns, including files in the Media Store. Downloads collection. If you're developing a camera app, for example, you don't need to request storage-related permissions because your app owns the images that you're writing to the media store.
From android 10 you can not to ask permissions to get files from storage. Works perfectly with all kinds of files (pdf, excel...) on my app on android 13 without any permissions.
So you just need to ask READ_EXTERNAL_STORAGE permission for SDK, less than android 10.
But if you need special files (for example which was created by Instagram app but not stored in usual storage) you should ask for permission from your list.
Also look for types of Media storage:
https://developer.android.com/reference/android/provider/MediaStore
About WRITE_EXTERNAL_STORAGE - you don`t need it since sdkVersion=29
EDIT: Was rewriting my app and want to add something:
It depends on what your app needs to do, but I have removed all kinds of storage permissions (only WRITE_EXTERNAL_STORAGE left for SDK less than 29) from my app, and just use ACTION_OPEN_DOCUMENT, ACTION_OPEN_DOCUMENT_TREE to have access for all kind of files (but not for system folders, ACTION_OPEN_DOCUMENT_TREE also have no access for download folder).
In my existing app(Android 10) I have a folder under /storage/emulated/0/<my_folder>. After looking to various sources on Google Developers I don't think that it's possible to longer access the /storage/emulated/0/<my_folder> directory under Android 11, because of the changes made in storage access permission.
Of course I can create these folder under Android 11 inside the so called "scoped storage" as mentioned by Google. But if a user updates the app from 10 to 11, how can I access the old folder for copying the files inside to the new folder inside "scoped storage" when I am on Android 11?
Or is there some other way to migrate this folder under /storage/emulated/0/<my_folder> safely?
With intent ACTION_OPEN_DOCUMENT_TREE you can let the user choose your <myfolder>.
For new installations use /storage/emulated/0/Documents/<my_folder> instead.
There is no reason to copy files or folders.
You can reclaim the permissions for your old app folder via SimpleStorage:
storageHelper.requestStorageAccess(
expectedStorageType = StorageType.EXTERNAL,
expectedBasePath = "<my_folder>"
)
Ever since Scoped storage introduction, you can no longer create your folders under root directory without special permission, I.E manage external storage, but i doubt play store will allow that access to your app if the core functionality isnt affected,
You can do one of the following
store your required files in respected folders [Recommended] (Documents for docs, DCIM for images/videos, Music for audio files and so on)
Require Permission to folder by open document tree intent (Last resort)
I am using Samsung A30s phone for accessing phone storage files. My files location in device is /storage/emulated/0/MY_FILES/. I kept some files in MY_FIlES directory but my below code does
not show any containing files under this directory.
So how can I get all files belong to this MY_FIlES directory in phone storage?
File Directory = new File("/storage/emulated/0/MY_FIlES/");
File[] files = Directory.listFiles();
But files return null;
Note: I have a permission(READ_EXTERNAL_STORAGE) to access file.
One important thing, I updated my phone in latest API. But before update, I used this path, " /sdcard/MY_FIlES/ and it worked fine.
First, never hardcode paths for apps that you plan to distribute. For those, please use methods on Context, Environment, or StorageVolume (Android 11 only) to find the base directory to use.
For Android 10 and 11, you need to add android:requestLegacyExternalStorage="true" to your <application> element in the manifest. This opts you into the legacy storage model, and your existing external storage code will work.
Note that in Android 11+, you will not be able to write to that directory, regardless of whether you have requested WRITE_EXTERNAL_STORAGE or not. Google would vastly prefer that you use the Storage Access Framework (e.g., ACTION_OPEN_DOCUMENT), so that users have more control over where files get placed on their devices or in their chosen cloud storage providers.
I would like to add something more to the #CommonsWare answer. As per the Android's storage update, they enforce scoped storage in the Android 11
version.
But to give developers additional time for testing, apps that target 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.
If your app opts out of scoped storage when running on Android 10 devices, it's recommended that you continue to set requestLegacyExternalStorage to true in your app's manifest file. That way, your app can continue to behave as expected on devices that run Android 10.
For more info on this, please check documentation
This question already has answers here:
Environment.getExternalStorageDirectory() deprecated in API level 29 java
(13 answers)
Closed 3 years ago.
I need to read a file stored in android root directory(/storage/emulated/0/MyFolder) while launching the app first time.
It was possible till API level 28 by using Environment.getExternalStorageDirectory(), But after I migrated to API level 29, Environment.getExternalStorageDirectory() deprecated and stopped working with below message.
This method was deprecated in API level 29. To improve user privacy,
direct access to shared/external storage devices is deprecated. When
an app targets Build.VERSION_CODES.Q, the path returned from this
method is no longer directly accessible to apps. Apps can continue to
access content stored on shared/external storage by migrating to
alternatives such as Context#getExternalFilesDir(String), MediaStore,
or Intent#ACTION_OPEN_DOCUMENT.
Also I tried Context().getExternalFilesDir(null) which was returning the following path only "/storage/emulated/0/Android/data/com.myapp.appid/files/", but I need to access a file in "/storage/emulated/0/" path.
So how to read the file in location "/storage/emulated/0/MyFolder" in legal way when running with target API level 29?
The only way is to ask the user to pick the file with Intent#ACTION_OPEN_DOCUMENT and then it is unlikely that the user will be able to pick that directory any way.
Google's stated intent for this change is to stop applications from making a proliferation of files/folders all over the place and give users control. The concept of files paths outside of your App's private directories no longer exists, you have to use MediaStore or SAF (Storage Access Framework) for non private stuff.
Going forward you will not be able to have your own App's public folder like this (unless on external SD card), you can only store stuff as Video, Image, Audio or Download (All other file types).
Note: that currently a number of Manufacturers on pre Android 10 provide a Document Provider that gives you access to the root of the Primary partition as well as the External SD card, but if you look at what is provided in the plain Android OS emulator images or Google's documentation you will not see a provided for the primary root partition as this would break Google's stated intent for this change.
See https://developer.android.com/training/data-storage/
and more specifically
https://developer.android.com/training/data-storage/shared/documents-files
You can ask the user to select a folder (which will be under the restricted public locations) and then you can programmatically access and check and files in this location. See https://developer.android.com/training/data-storage/shared/documents-files#grant-access-directory
You can ask the user once and then store the permission they have given you to access files/folders with https://developer.android.com/training/data-storage/shared/documents-files#persist-permissions
Note:
There is a temporary workaround until Android 11 by enabling legacy mode.