Environment.getExternalStorageDirectory does not return the path to the removable storage
According to the source, getExternalStorageDirectory
is implemented to return whatever is set as "external storage" in the device environment:
public static File getExternalStorageDirectory() {
return EXTERNAL_STORAGE_DIRECTORY;
}
and EXTERNAL_STORAGE_DIRECTORY
is:
private static final File EXTERNAL_STORAGE_DIRECTORY
= getDirectory("EXTERNAL_STORAGE", "/sdcard");
static File getDirectory(String variableName, String defaultPath) {
String path = System.getenv(variableName);
return path == null ? new File(defaultPath) : new File(path);
}
In contrast, getExternalStoragePublicDirectory(String type)
requires one of these strings:
DIRECTORY_MUSIC, DIRECTORY_PODCASTS, DIRECTORY_RINGTONES, DIRECTORY_ALARMS, DIRECTORY_NOTIFICATIONS, DIRECTORY_PICTURES, DIRECTORY_MOVIES, DIRECTORY_DOWNLOADS, or DIRECTORY_DCIM. May not be null.
so it is not meant to return the sd-card root.
An alternative:
Finally, getExternalStorageState()
will return the filesystem mounted in /mnt/sdcard/
. According to CommonsWare in this answer: Find an external SD card location, there is no way to directly get the external sdcard (if it even exist).
An alternative would be to check isExternalStorageRemovable ()
and give a manual option if it is false.
Environment.getExternalStorageDirectory() deprecated in API level 29 java
Use getExternalFilesDir()
, getExternalCacheDir()
, or getExternalMediaDirs()
(methods on Context
) instead of Environment.getExternalStorageDirectory()
.
Or, modify mPhotoEditor
to be able to work with a Uri
, then:
Use
ACTION_CREATE_DOCUMENT
to get aUri
to a location of the user's choosing, orUse
MediaStore
,ContentResolver
, andinsert()
to get aUri
for a particular type of media (e.g., an image) — see this sample app that demonstrates doing this for downloading MP4 videos from a Web site
Also, note that your Uri.fromFile
with ACTION_MEDIA_SCANNER_SCAN_FILE
should be crashing on Android 7.0+ with a FileUriExposedException
. On Android Q, only the MediaStore
/insert()
option will get your content indexed by the MediaStore
quickly.
Note that you can opt out of these "scoped storage" changes on Android 10 and 11, if your targetSdkVersion
is below 30, using android:requestLegacyExternalStorage="true"
in the <application>
element of the manifest. This is not a long-term solution, as your targetSdkVersion
will need to be 30 or higher sometime in 2021 if you are distributing your app through the Play Store (and perhaps elsewhere).
environment.getExternalStorageDirectory() shows path which doesn't even exist
The path exists for your app's process.
Android, starting with 4.2, supports multiple accounts per device (originally just for tablets, now for all devices starting with 5.0). Each account gets its own distinct area for internal and external storage. The framework will return paths from methods like getExternalStorageDirectory()
that are correct for the current account holder that is running your app. What these locations map to in terms of actual filesystem locations is up to Android, as part of its effort to secure access to storage.
Related Topics
Read the Package Name of an Android APK
Timepicker in Preferencescreen
Android Hide/Unhide App Icon Programmatically
Programmatically Update Widget from Activity/Service/Receiver
Missing "<Sdk>/Extras/Google/Google_Play_Services/Libproject" Folder After Update to Revision 30
How to Add an Image on Edittext
Android - Webview Language Changes Abruptly on Android 7.0 and Above
How to Get the Correct Orientation of the Image Selected from the Default Image Gallery
Android Animation Is Not Finished in Onanimationend
How to Display Custom View in Actionbar
Multiline Edittext with Done Softinput Action Label on 2.3
How to Enable Logging for Apache Commons Httpclient on Android
Usb Device Access Pop-Up Suppression
Using Viewpagerindicator Library with Android Studio and Gradle
Refreshing Data in Recyclerview and Keeping Its Scroll Position