I'm returning the external files directory for API 23 and below.
I want to check that the media is mounted, however this test is always passed, although the WRITE_EXTERNAL_STORAGE permission is not yet declared in the manifest.
I'm not sure, but I thought the test should fail for API 18 and below if the WRITE_EXTERNAL_STORAGE is not declared/enabled?
A permission denied exception is then thrown when trying to access this directory.
if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
return getExternalFilesDir(null).getAbsolutePath() + "/update_files";
}
Related
I would like to make a file manager app targeting API level 31 that requires access to all files on the device. To do this, I have followed the guidance here: https://developer.android.com/training/data-storage/manage-all-files.
I have added the MANAGE_EXTERNAL_STORAGE permission and allowed it in the device settings. Here is the Kotlin code I'm using to list the root directories on the device:
val file = Environment.getStorageDirectory()
// ensure we have file access permission
if (Environment.isExternalStorageManager() && Environment.isExternalStorageManager(file)) {
Log.d("FileManager", "Exists: ${file.exists()}")
Log.d("FileManager", "Is directory: ${file.isDirectory}")
Log.d("FileManager", "List files: ${file.listFiles()}")
}
Here is the output:
D/FileManager: Exists: true
D/FileManager: Is directory: true
D/FileManager: List files: null
As you can see, the directory exists, but listFiles() unexpectedly returns null. Given this, how can I navigate all the files on the device, starting from the root directory?
I have seen similar questions, but their answers all seem outdated or unusable. Here are some of the suggestions I've found:
Use Environment.getExternalStorageDirectory()
This works, but is deprecated in API level 31.
Use android:requestLegacyExternalStorage="true"
This is outdated.
Use ActivityResultContracts
This does not apply to a custom file manager app.
Given this, how can I navigate all the files on the device, starting from the root directory?
You can't, at least on unrooted devices. Even with MANAGE_EXTERNAL_STORAGE, all that you have access to is external storage, not the entire device filesystem.
Use Environment.getExternalStorageDirectory() — This works, but is deprecated in API level 31.
It is now undeprecated, as of Android 12L and Android 13 DP2. Hopefully the public documentation will reflect this when Android 13 ships later this year.
Use android:requestLegacyExternalStorage="true" — This is outdated.
You still want it for Android 10 support.
Adding a uses permission MANAGE_EXTERNAL_STORAGE to manifest file is not enough to get 'all files access'.
You also at runtime have to start an intent for Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION.
I uploaded several files to folder "/sdcard/Books/LadySusan" on my android emulator. When I check if file in folder exist, expression
new File("/sdcard/Books/LadySusan/ladysusan_1_austen_64kb.mp3").exists()
returns true, file exists in folder, but when I use
new File("/sdcard/Books/LadySusan").listFiles()
it returns empty array, not null but File[0]. I have permissions to read files from SD card
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
and code to request them. Any idea what can be wrong?
Finally I found. It seems to me there is a bug in Android SDK (10.0+). When I started emulator with Android 9.0, it returns files as I expected.
It is not a bug. As of Android 10, external storage access is scoped to app files and media.
This means that your application can only access the files in the app-specific directory (which can be retrieved in code with getExternalFilesDir()) or media in the media store.
As long as you target an Android version lower than API level 30 (Android 11) you can get away with accessing the external storage via the following permission:
<application android:requestLegacyExternalStorage="true" ... >
I have an app that needs to write files to external storage.
In manifest I've added
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
In the activity I am calling
ActivityCompat.requestPermissions(this, STORAGE_PERMISSIONS, PERMISSION_REQUEST_RW_EXTERNAL_STORAGE);
Where:
private static final int PERMISSION_REQUEST_RW_EXTERNAL_STORAGE = 783;
private static final String[] STORAGE_PERMISSIONS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};
Of course I'm granting everything and I can see in "onRequestPermissionsResult" the grants received by the app.
After all of that, when trying to create a file in external storage I am getting permissions denied.
java.io.IOException: Permission denied
Running on:
Android 8 (Oreo)
compileSdkVersion 27
minSdkVersion 23
targetSdkVersion 27
EDIT:
I am trying to write this directory: /storage/emulated/0/6666-6433/DCIM/Camera/. In previous state I'm listing video files on local storage and getting files in this directory. reading the files using this path is working as expected.
I cannot create new folder any way, it always return false when use mkdirs. I am using Android 6.0.1 in android studio debug mode.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />`
String folder_main = "NewFolder";
Boolean success = false;
File f = new File(Environment.getExternalStorageDirectory(),folder_main
);
if (!f.exists()) {
Log.d("path","not exist");
success=f.mkdirs();
}
else
{
Log.d("path","exist");
}
Log.d("path",success.toString());
I didn't use write permission since in this docs
Starting in API level 19, this permission is not required to
read/write files in your application-specific directories returned by
getExternalFilesDir(String) and getExternalCacheDir().
The doc says you can read/write files only in the directories returned by getExternalFilesDir(String) and getExternalCacheDir() without write permission. But you get directory path by Environment.getExternalStorageDirectory().
Javadoc of Environment.getExternalStorageDirectory() says.
Writing to this path requires the WRITE_EXTERNAL_STORAGE permission, and starting in KITKAT, read access requires the READ_EXTERNAL_STORAGE permission, which is automatically granted if you hold the write permission.
Starting in KITKAT, if your application only needs to store internal data, consider using getExternalFilesDir(String), getExternalCacheDir(), or getExternalMediaDirs(), which require no permissions to read or write.
In case of making directory in external storage in android app I use this code:
File mDirectory = new File(Environment.getExternalStorageDirectory() + "/myDir");
if (!mDirectory.exists()) {
mDirectory.mkdirs();
if (!mDirectory.mkdirs()) {
Log.e("App", "failed to create directory");
}
}
but the directory didn't created and all the time the error message shown up in logcat:
App: failed to create directory
I also use both mkdir() and mkdirs(), but the result is same. where is the mistake?
updated:
AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
What Android Version are you running this app on ? This quote from the Android Developer Website says
If the device is running Android 6.0 (API level 23) or higher, and the app's targetSdkVersion is 23 or higher, the app requests permissions from the user at run-time. The user can revoke the permissions at any time, so the app needs to check whether it has the permissions every time it runs.
If the device is running Android 5.1 (API level 22) or lower, or the app's targetSdkVersion is 22 or lower, the system asks the user to grant the permissions when the user installs the app.
Now there is a notion of Dangerous permissions. That are permissions the user needs to grant at runtime and WRITE_EXTERNAL_STORAGE is one of those
This tutorial on the Android Dev website will teach you how to request permission at runtime
You are calling mkdirs twice. The first call creates the directory. The second call returns false, because the directory already exists.