wirte on external sd card does not work - android

My app doesn't seem to have writing permissions on my external sd card. I can read from it, but writing does only work on the internal one (sdcard0).
When i try
File f = new File("/storacge/sdcard1/Test/file.mp3");
boolean b = f.delete();
then b is false and the file still exists. But i can play it with MediaPlayer.
I have <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> in my Manifest
What am i doing wrong?

1)You need to ask for runtime permissions
2)Don't assume that the path is /storage/sdcard1. That varies between devices. Request the name via getExternalFilesDirs

If you're working on Android 6.0 or higher you will have to request for permissions exactly where you need them.
Create a method in your activity as such:
public void askForWritePermissions(){
//If android marshmellow or higher
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){
//If permissions are not granted
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED ){
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},2);
}
}
}
And call the above method on whichever event you need. After the user grants access or doesn't grant access to the permissions, onRequestPermissionsResult() is called so make sure you handle that method appropriately.

Related

Android 11 - Install an apk using a system app [duplicate]

I am getting
open failed: EACCES (Permission denied)
on the line OutputStream myOutput = new FileOutputStream(outFileName);
I checked the root, and I tried android.permission.WRITE_EXTERNAL_STORAGE.
How can I fix this problem?
try {
InputStream myInput;
myInput = getAssets().open("XXX.db");
// Path to the just created empty db
String outFileName = "/data/data/XX/databases/"
+ "XXX.db";
// Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
// Transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
buffer = null;
outFileName = null;
}
catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Google has a new feature on Android Q: filtered view for external storage. A quick fix for that is to add this code in the AndroidManifest.xml file:
<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
You can read more about it here: https://developer.android.com/training/data-storage/use-cases
Edit: I am starting to get downvotes because this answer is out of date for Android 11. So whoever sees this answer please go to the link above and read the instructions.
For API 23+ you need to request the read/write permissions even if they are already in your manifest.
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
/**
* Checks if the app has permission to write to device storage
*
* If the app does not has permission then the user will be prompted to grant permissions
*
* #param activity
*/
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
For official documentation about requesting permissions for API 23+, check https://developer.android.com/training/permissions/requesting.html
I had the same problem... The <uses-permission was in the wrong place. This is right:
<manifest>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
...
<application>
...
<activity>
...
</activity>
</application>
</manifest>
The uses-permission tag needs to be outside the application tag.
Add android:requestLegacyExternalStorage="true" to the Android Manifest
It's worked with Android 10 (Q) at SDK 29+
or After migrating Android X.
<application
android:name=".MyApplication"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon=""
android:label=""
android:largeHeap="true"
android:supportsRtl=""
android:theme=""
android:requestLegacyExternalStorage="true">
I have observed this once when running the application inside the emulator. In the emulator settings, you need to specify the size of external storage ("SD Card") properly. By default, the "external storage" field is empty, and that probably means there is no such device and EACCES is thrown even if permissions are granted in the manifest.
In addition to all the answers, make sure you're not using your phone as a USB storage.
I was having the same problem on HTC Sensation on USB storage mode enabled. I can still debug/run the app, but I can't save to external storage.
My issue was with "TargetApi(23)" which is needed if your minSdkVersion is bellow 23.
So, I have request permission with the following snippet
protected boolean shouldAskPermissions() {
return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
}
#TargetApi(23)
protected void askPermissions() {
String[] permissions = {
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"
};
int requestCode = 200;
requestPermissions(permissions, requestCode);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
if (shouldAskPermissions()) {
askPermissions();
}
}
Be aware that the solution:
<application ...
android:requestLegacyExternalStorage="true" ... >
Is temporary, sooner or later your app should be migrated to use Scoped Storage.
In Android 10, you can use the suggested solution to bypass the system restrictions, but in Android 11 (R) it is mandatory to use scoped storage, and your app might break if you kept using the old logic!
This video might be a good help.
Android 10 (API 29) introduces Scoped Storage. Changing your manifest to request legacy storage is not a long-term solution.
I fixed the issue when I replaced my previous instances of Environment.getExternalStorageDirectory() (which is deprecated with API 29) with context.getExternalFilesDir(null).
Note that context.getExternalFilesDir(type) can return null if the storage location isn't available, so be sure to check that whenever you're checking if you have external permissions.
Read more here.
I'm experiencing the same. What I found is that if you go to Settings -> Application Manager -> Your App -> Permissions -> Enable Storage, it solves the issue.
It turned out, it was a stupid mistake since I had my phone still connected to the desktop PC and didn't realize this.
So I had to turn off the USB connection and everything worked fine.
I had the same problem on Samsung Galaxy Note 3, running CM 12.1. The issue for me was that i had
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18"/>
and had to use it to take and store user photos. When I tried to load those same photos in ImageLoader i got the (Permission denied) error. The solution was to explicitly add
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
since the above permission only limits the write permission up to API version 18, and with it the read permission.
In addition to all answers, if the clients are using Android 6.0, Android added new permission model for (Marshmallow).
Trick: If you are targeting version 22 or below, your application will request all permissions at install time just as it would on any device running an OS below Marshmallow. If you are trying on the emulator then from android 6.0 onwards you need to explicitly go the settings->apps-> YOURAPP -> permissions and change the permission if you have given any.
Strangely after putting a slash "/" before my newFile my problem was solved. I changed this:
File myFile= new File(Environment.getExternalStorageDirectory() + "newFile");
to this:
File myFile= new File(Environment.getExternalStorageDirectory() + "/newFile");
UPDATE:
as mentioned in the comments, the right way to do this is:
File myFile= new File(Environment.getExternalStorageDirectory(), "newFile");
I had the same problem and none of suggestions helped. But I found an interesting reason for that, on a physical device, Galaxy Tab.
When USB storage is on, external storage read and write permissions don't have any effect.
Just turn off USB storage, and with the correct permissions, you'll have the problem solved.
I would expect everything below /data to belong to "internal storage". You should, however, be able to write to /sdcard.
Change a permission property in your /system/etc/permission/platform.xml
and group need to mentioned as like below.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
<group android:gid="sdcard_rw" />
<group android:gid="media_rw" />
</uses-permission>
I had the same error when was trying to write an image in DCIM/camera folder on Galaxy S5 (android 6.0.1) and I figured out that only this folder is restricted. I simply could write into DCIM/any folder but not in camera.
This should be brand based restriction/customization.
Maybe the answer is this:
on the API >= 23 devices, if you install app (the app is not system app), you should check the storage permission in "Setting - applications", there is permission list for every app, you should check it on! try
To store a file in a directory which is foreign to the app's directory is restricted above API 29+. So to generate a new file or to create a new file use your application directory like this :-
So the correct approach is :-
val file = File(appContext.applicationInfo.dataDir + File.separator + "anyRandomFileName/")
You can write any data into this generated file !
The above file is accessible and would not throw any exception because it resides in your own developed app's directory.
The other option is android:requestLegacyExternalStorage="true" in manifest application tag as suggested by Uriel but its not a permanent solution !
When your application belongs to the system application, it can't access the SD card.
keep in mind that even if you set all the correct permissions in the manifest:
The only place 3rd party apps are allowed to write on your external card are "their own directories"
(i.e. /sdcard/Android/data/)
trying to write to anywhere else: you will get exception:
EACCES (Permission denied)
Environment.getExternalStoragePublicDirectory();
When using this deprecated method from Android 29 onwards you will receive the same error:
java.io.FileNotFoundException: open failed: EACCES (Permission denied)
Resolution here:
getExternalStoragePublicDirectory deprecated in Android Q
In my case I was using a file picker library which returned the path to external storage but it started from /root/. And even with the WRITE_EXTERNAL_STORAGE permission granted at runtime I still got error EACCES (Permission denied).
So use Environment.getExternalStorageDirectory() to get the correct path to external storage.
Example:
Cannot write: /root/storage/emulated/0/newfile.txt
Can write: /storage/emulated/0/newfile.txt
boolean externalStorageWritable = isExternalStorageWritable();
File file = new File(filePath);
boolean canWrite = file.canWrite();
boolean isFile = file.isFile();
long usableSpace = file.getUsableSpace();
Log.d(TAG, "externalStorageWritable: " + externalStorageWritable);
Log.d(TAG, "filePath: " + filePath);
Log.d(TAG, "canWrite: " + canWrite);
Log.d(TAG, "isFile: " + isFile);
Log.d(TAG, "usableSpace: " + usableSpace);
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
Output 1:
externalStorageWritable: true
filePath: /root/storage/emulated/0/newfile.txt
isFile: false
usableSpace: 0
Output 2:
externalStorageWritable: true
filePath: /storage/emulated/0/newfile.txt
isFile: true
usableSpace: 1331007488
I am creating a folder under /data/ in my init.rc (mucking around with the aosp on Nexus 7) and had exactly this problem.
It turned out that giving the folder rw (666) permission was not sufficient and it had to be rwx (777) then it all worked!
The post 6.0 enforcement of storage permissions can be bypassed if you have a rooted device via these adb commands:
root#msm8996:/ # getenforce
getenforce
Enforcing
root#msm8996:/ # setenforce 0
setenforce 0
root#msm8996:/ # getenforce
getenforce
Permissive
i faced the same error on xiaomi devices (android 10 ). The following code fixed my problem.
Libraries: Dexter(https://github.com/Karumi/Dexter) and Image picker(https://github.com/Dhaval2404/ImagePicker)
Add manifest ( android:requestLegacyExternalStorage="true")
public void showPickImageSheet(AddImageModel model) {
BottomSheetHelper.showPickImageSheet(this, new BottomSheetHelper.PickImageDialogListener() {
#Override
public void onChooseFromGalleryClicked(Dialog dialog) {
selectedImagePickerPosition = model.getPosition();
Dexter.withContext(OrderReviewActivity.this) .withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE)
.withListener(new MultiplePermissionsListener() {
#Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (report.areAllPermissionsGranted()) {
ImagePicker.with(OrderReviewActivity.this)
.galleryOnly()
.compress(512)
.maxResultSize(852,480)
.start();
}
}
#Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> list, PermissionToken permissionToken) {
permissionToken.continuePermissionRequest();
}
}).check();
dialog.dismiss();
}
#Override
public void onTakePhotoClicked(Dialog dialog) {
selectedImagePickerPosition = model.getPosition();
ImagePicker.with(OrderReviewActivity.this)
.cameraOnly()
.compress(512)
.maxResultSize(852,480)
.start();
dialog.dismiss();
}
#Override
public void onCancelButtonClicked(Dialog dialog) {
dialog.dismiss();
}
});
}
In my case the error was appearing on the line
target.createNewFile();
since I could not create a new file on the sd card,so I had to use the DocumentFile approach.
documentFile.createFile(mime, target.getName());
For the above question the problem may be solved with this approach,
fos=context.getContentResolver().openOutputStream(documentFile.getUri());
See this thread too,
How to use the new SD card access API presented for Android 5.0 (Lollipop)?
I Use the below process to handle the case with android 11 and targetapi30
As pre-created file dir as per scoped storage in my case in root dir files//<Image/Video... as per requirement>
Copy picked file and copy the file in cache directory at the time of picking from my external storage
Then at a time to upload ( on my send/upload button click) copy the file from cache dir to my scoped storage dir and then do my upload process
use this solution due to at time upload app in play store it generates warning for MANAGE_EXTERNAL_STORAGE permission and sometimes rejected from play store in my case.
Also as we used target API 30 so we can't share or forward file from our internal storage to app
2022 Kotlin way to ask permission:
private val writeStoragePermissionResult =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->}
private fun askForStoragePermission(): Boolean =
if (hasPermissions(
requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
) {
true
} else {
writeStoragePermissionResult.launch(
arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
)
)
false
}
fun hasPermissions(context: Context, vararg permissions: String): Boolean = permissions.all {
ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}

How to read a file directly from external download directory on Android 10 (Q)

I am trying to read a file from the download folder on Android Q by doing this:
File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
File f = new File(downloadDir, "some-existing-file");
if(!f.exists()) {
throw new IllegalStateException();
}
Uri furi = Uri.fromFile(f);
try {
ParcelFileDescriptor des = getContentResolver().openFileDescriptor(
furi, "r", null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
I also set android:requestLegacyExternalStorage="true" in the manifest, and requested WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE runtime permissions.
The file exists but when trying to open the file descriptor, an exception arises:
java.io.FileNotFoundException: open failed: EACCES (Permission denied).
I read the changes made in Android Q storage, but could not figure out how can I just read the file without having user interaction.
Thanks!
From Android 6 (Marshmallow) some of critical permissions should be granted at runtime by the user so he/she will know what things can your app access.
this link is all what you need
EDIT
add these to manifest
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
then add this code to your oncreate method
if (android.os.Build.VERSION.SDK_INT >= 23 && (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(
this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
2000);
}
this will popup the user a dialog to agree permissions. if the user agrees onRequestPermissionsResult method will be called, so override onRequestPermissionsResult like this
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && requestCode == 2000) {
//do what you want with files
}
}
just pay attention that I set request code to 2000. it's optional.
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.
Copied from Android documents.docs
After too many hours of trying to figure out what the hell is going on, I managed to find a solution.
I addded to the manifest:
android:requestLegacyExternalStorage="true"
When rebuilding and reinstalling directly from Android Studio, the build system or android runtime does not register a change in the manifest, and the request for requestLegacyExternalStorage does not register.
I fixed it by completely uninstalling the app: adb uninstall com.example.app and installing it again from android studio.

How to create a public directory on the external storage?

I am trying to save public files on the external storage.
I am following the example from Android Developers page:
https://developer.android.com/training/data-storage/files#PublicFiles
First I tried to create a directory "mydocuments" in the public directory DIRECTORY_DOCUMENTS. The code is as simple as
TextView tv= findViewById(R.id.myTextview);
// Get the directory for the user's public pictures directory.
File documents= Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS);
tv.append("\n documents directory=" + documents);
File file = new File(documents, "mydocuments");
tv.append("\n\nDirectory to be created=" + file);
if (file.exists())
tv.append("\n\nFile already exists:" + file.getAbsolutePath());
else{
if (!file.mkdirs())
tv.append("\n\nDirectory not created:" + file.getAbsolutePath());
I added permissions in the manifest file
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE">
</uses-permission>
However when I run this in a device (be virtual or physical) the result is always the same:
documents directory=/storage/emulated/0/Documents
Directory to be created=/storage/emulated/0/Documents/mydocuments
Directory not created:/storage/emulated/0/Download/mydocuments
How to make the Documents directory writeable?
Thank you in advance.
You are #1278 with this problem this year.
For Android 6+ you have to add code to ask the user to confirm the permissions you requested in manifest file.
Google for runtime permissions.
You could also go to the settings of your app and toggle the storage permission to on.
Thanks to #greenapps suggestion I solved my problem. This is the simplest solution I found to write in the Documents directory on the SD card, as explained in
https://developer.android.com/training/permissions/requesting
I have copied some of that here:
1.- First ask for user permissions somewhere at the begining of the code:
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
MY_PERMISSIONS);
where I previously defined the constant
final int MY_PERMISSIONS=1;
2.- Then implement my code above to write on the SD card inside the method
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// task you need to do.
writeSD(); // this is the code to write on the SD card shown above
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
tv.append("\n\n No permission given");
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
This solves the issue for me. The first time it is executed, a dialog opens asking for the permissions. After that It is allowed to read the contents of the sdcard and to write in the public directories DOCUMENTS, PICTURES, DOWNLOADS, etc.

TextToSpeech addSpeech(String key_string , String path) is not working [duplicate]

I am getting
open failed: EACCES (Permission denied)
on the line OutputStream myOutput = new FileOutputStream(outFileName);
I checked the root, and I tried android.permission.WRITE_EXTERNAL_STORAGE.
How can I fix this problem?
try {
InputStream myInput;
myInput = getAssets().open("XXX.db");
// Path to the just created empty db
String outFileName = "/data/data/XX/databases/"
+ "XXX.db";
// Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
// Transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
buffer = null;
outFileName = null;
}
catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Google has a new feature on Android Q: filtered view for external storage. A quick fix for that is to add this code in the AndroidManifest.xml file:
<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
You can read more about it here: https://developer.android.com/training/data-storage/use-cases
Edit: I am starting to get downvotes because this answer is out of date for Android 11. So whoever sees this answer please go to the link above and read the instructions.
For API 23+ you need to request the read/write permissions even if they are already in your manifest.
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
/**
* Checks if the app has permission to write to device storage
*
* If the app does not has permission then the user will be prompted to grant permissions
*
* #param activity
*/
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
For official documentation about requesting permissions for API 23+, check https://developer.android.com/training/permissions/requesting.html
I had the same problem... The <uses-permission was in the wrong place. This is right:
<manifest>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
...
<application>
...
<activity>
...
</activity>
</application>
</manifest>
The uses-permission tag needs to be outside the application tag.
Add android:requestLegacyExternalStorage="true" to the Android Manifest
It's worked with Android 10 (Q) at SDK 29+
or After migrating Android X.
<application
android:name=".MyApplication"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon=""
android:label=""
android:largeHeap="true"
android:supportsRtl=""
android:theme=""
android:requestLegacyExternalStorage="true">
I have observed this once when running the application inside the emulator. In the emulator settings, you need to specify the size of external storage ("SD Card") properly. By default, the "external storage" field is empty, and that probably means there is no such device and EACCES is thrown even if permissions are granted in the manifest.
In addition to all the answers, make sure you're not using your phone as a USB storage.
I was having the same problem on HTC Sensation on USB storage mode enabled. I can still debug/run the app, but I can't save to external storage.
My issue was with "TargetApi(23)" which is needed if your minSdkVersion is bellow 23.
So, I have request permission with the following snippet
protected boolean shouldAskPermissions() {
return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
}
#TargetApi(23)
protected void askPermissions() {
String[] permissions = {
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"
};
int requestCode = 200;
requestPermissions(permissions, requestCode);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
if (shouldAskPermissions()) {
askPermissions();
}
}
Be aware that the solution:
<application ...
android:requestLegacyExternalStorage="true" ... >
Is temporary, sooner or later your app should be migrated to use Scoped Storage.
In Android 10, you can use the suggested solution to bypass the system restrictions, but in Android 11 (R) it is mandatory to use scoped storage, and your app might break if you kept using the old logic!
This video might be a good help.
Android 10 (API 29) introduces Scoped Storage. Changing your manifest to request legacy storage is not a long-term solution.
I fixed the issue when I replaced my previous instances of Environment.getExternalStorageDirectory() (which is deprecated with API 29) with context.getExternalFilesDir(null).
Note that context.getExternalFilesDir(type) can return null if the storage location isn't available, so be sure to check that whenever you're checking if you have external permissions.
Read more here.
I'm experiencing the same. What I found is that if you go to Settings -> Application Manager -> Your App -> Permissions -> Enable Storage, it solves the issue.
It turned out, it was a stupid mistake since I had my phone still connected to the desktop PC and didn't realize this.
So I had to turn off the USB connection and everything worked fine.
I had the same problem on Samsung Galaxy Note 3, running CM 12.1. The issue for me was that i had
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18"/>
and had to use it to take and store user photos. When I tried to load those same photos in ImageLoader i got the (Permission denied) error. The solution was to explicitly add
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
since the above permission only limits the write permission up to API version 18, and with it the read permission.
In addition to all answers, if the clients are using Android 6.0, Android added new permission model for (Marshmallow).
Trick: If you are targeting version 22 or below, your application will request all permissions at install time just as it would on any device running an OS below Marshmallow. If you are trying on the emulator then from android 6.0 onwards you need to explicitly go the settings->apps-> YOURAPP -> permissions and change the permission if you have given any.
Strangely after putting a slash "/" before my newFile my problem was solved. I changed this:
File myFile= new File(Environment.getExternalStorageDirectory() + "newFile");
to this:
File myFile= new File(Environment.getExternalStorageDirectory() + "/newFile");
UPDATE:
as mentioned in the comments, the right way to do this is:
File myFile= new File(Environment.getExternalStorageDirectory(), "newFile");
I had the same problem and none of suggestions helped. But I found an interesting reason for that, on a physical device, Galaxy Tab.
When USB storage is on, external storage read and write permissions don't have any effect.
Just turn off USB storage, and with the correct permissions, you'll have the problem solved.
I would expect everything below /data to belong to "internal storage". You should, however, be able to write to /sdcard.
Change a permission property in your /system/etc/permission/platform.xml
and group need to mentioned as like below.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
<group android:gid="sdcard_rw" />
<group android:gid="media_rw" />
</uses-permission>
I had the same error when was trying to write an image in DCIM/camera folder on Galaxy S5 (android 6.0.1) and I figured out that only this folder is restricted. I simply could write into DCIM/any folder but not in camera.
This should be brand based restriction/customization.
Maybe the answer is this:
on the API >= 23 devices, if you install app (the app is not system app), you should check the storage permission in "Setting - applications", there is permission list for every app, you should check it on! try
To store a file in a directory which is foreign to the app's directory is restricted above API 29+. So to generate a new file or to create a new file use your application directory like this :-
So the correct approach is :-
val file = File(appContext.applicationInfo.dataDir + File.separator + "anyRandomFileName/")
You can write any data into this generated file !
The above file is accessible and would not throw any exception because it resides in your own developed app's directory.
The other option is android:requestLegacyExternalStorage="true" in manifest application tag as suggested by Uriel but its not a permanent solution !
When your application belongs to the system application, it can't access the SD card.
keep in mind that even if you set all the correct permissions in the manifest:
The only place 3rd party apps are allowed to write on your external card are "their own directories"
(i.e. /sdcard/Android/data/)
trying to write to anywhere else: you will get exception:
EACCES (Permission denied)
Environment.getExternalStoragePublicDirectory();
When using this deprecated method from Android 29 onwards you will receive the same error:
java.io.FileNotFoundException: open failed: EACCES (Permission denied)
Resolution here:
getExternalStoragePublicDirectory deprecated in Android Q
In my case I was using a file picker library which returned the path to external storage but it started from /root/. And even with the WRITE_EXTERNAL_STORAGE permission granted at runtime I still got error EACCES (Permission denied).
So use Environment.getExternalStorageDirectory() to get the correct path to external storage.
Example:
Cannot write: /root/storage/emulated/0/newfile.txt
Can write: /storage/emulated/0/newfile.txt
boolean externalStorageWritable = isExternalStorageWritable();
File file = new File(filePath);
boolean canWrite = file.canWrite();
boolean isFile = file.isFile();
long usableSpace = file.getUsableSpace();
Log.d(TAG, "externalStorageWritable: " + externalStorageWritable);
Log.d(TAG, "filePath: " + filePath);
Log.d(TAG, "canWrite: " + canWrite);
Log.d(TAG, "isFile: " + isFile);
Log.d(TAG, "usableSpace: " + usableSpace);
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
Output 1:
externalStorageWritable: true
filePath: /root/storage/emulated/0/newfile.txt
isFile: false
usableSpace: 0
Output 2:
externalStorageWritable: true
filePath: /storage/emulated/0/newfile.txt
isFile: true
usableSpace: 1331007488
I am creating a folder under /data/ in my init.rc (mucking around with the aosp on Nexus 7) and had exactly this problem.
It turned out that giving the folder rw (666) permission was not sufficient and it had to be rwx (777) then it all worked!
The post 6.0 enforcement of storage permissions can be bypassed if you have a rooted device via these adb commands:
root#msm8996:/ # getenforce
getenforce
Enforcing
root#msm8996:/ # setenforce 0
setenforce 0
root#msm8996:/ # getenforce
getenforce
Permissive
i faced the same error on xiaomi devices (android 10 ). The following code fixed my problem.
Libraries: Dexter(https://github.com/Karumi/Dexter) and Image picker(https://github.com/Dhaval2404/ImagePicker)
Add manifest ( android:requestLegacyExternalStorage="true")
public void showPickImageSheet(AddImageModel model) {
BottomSheetHelper.showPickImageSheet(this, new BottomSheetHelper.PickImageDialogListener() {
#Override
public void onChooseFromGalleryClicked(Dialog dialog) {
selectedImagePickerPosition = model.getPosition();
Dexter.withContext(OrderReviewActivity.this) .withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE)
.withListener(new MultiplePermissionsListener() {
#Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (report.areAllPermissionsGranted()) {
ImagePicker.with(OrderReviewActivity.this)
.galleryOnly()
.compress(512)
.maxResultSize(852,480)
.start();
}
}
#Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> list, PermissionToken permissionToken) {
permissionToken.continuePermissionRequest();
}
}).check();
dialog.dismiss();
}
#Override
public void onTakePhotoClicked(Dialog dialog) {
selectedImagePickerPosition = model.getPosition();
ImagePicker.with(OrderReviewActivity.this)
.cameraOnly()
.compress(512)
.maxResultSize(852,480)
.start();
dialog.dismiss();
}
#Override
public void onCancelButtonClicked(Dialog dialog) {
dialog.dismiss();
}
});
}
In my case the error was appearing on the line
target.createNewFile();
since I could not create a new file on the sd card,so I had to use the DocumentFile approach.
documentFile.createFile(mime, target.getName());
For the above question the problem may be solved with this approach,
fos=context.getContentResolver().openOutputStream(documentFile.getUri());
See this thread too,
How to use the new SD card access API presented for Android 5.0 (Lollipop)?
I Use the below process to handle the case with android 11 and targetapi30
As pre-created file dir as per scoped storage in my case in root dir files//<Image/Video... as per requirement>
Copy picked file and copy the file in cache directory at the time of picking from my external storage
Then at a time to upload ( on my send/upload button click) copy the file from cache dir to my scoped storage dir and then do my upload process
use this solution due to at time upload app in play store it generates warning for MANAGE_EXTERNAL_STORAGE permission and sometimes rejected from play store in my case.
Also as we used target API 30 so we can't share or forward file from our internal storage to app
2022 Kotlin way to ask permission:
private val writeStoragePermissionResult =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->}
private fun askForStoragePermission(): Boolean =
if (hasPermissions(
requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
) {
true
} else {
writeStoragePermissionResult.launch(
arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
)
)
false
}
fun hasPermissions(context: Context, vararg permissions: String): Boolean = permissions.all {
ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}

Exception 'open failed: EACCES (Permission denied)' on Android

I am getting
open failed: EACCES (Permission denied)
on the line OutputStream myOutput = new FileOutputStream(outFileName);
I checked the root, and I tried android.permission.WRITE_EXTERNAL_STORAGE.
How can I fix this problem?
try {
InputStream myInput;
myInput = getAssets().open("XXX.db");
// Path to the just created empty db
String outFileName = "/data/data/XX/databases/"
+ "XXX.db";
// Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
// Transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
buffer = null;
outFileName = null;
}
catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Google has a new feature on Android Q: filtered view for external storage. A quick fix for that is to add this code in the AndroidManifest.xml file:
<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
You can read more about it here: https://developer.android.com/training/data-storage/use-cases
Edit: I am starting to get downvotes because this answer is out of date for Android 11. So whoever sees this answer please go to the link above and read the instructions.
For API 23+ you need to request the read/write permissions even if they are already in your manifest.
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
/**
* Checks if the app has permission to write to device storage
*
* If the app does not has permission then the user will be prompted to grant permissions
*
* #param activity
*/
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
For official documentation about requesting permissions for API 23+, check https://developer.android.com/training/permissions/requesting.html
I had the same problem... The <uses-permission was in the wrong place. This is right:
<manifest>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
...
<application>
...
<activity>
...
</activity>
</application>
</manifest>
The uses-permission tag needs to be outside the application tag.
Add android:requestLegacyExternalStorage="true" to the Android Manifest
It's worked with Android 10 (Q) at SDK 29+
or After migrating Android X.
<application
android:name=".MyApplication"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon=""
android:label=""
android:largeHeap="true"
android:supportsRtl=""
android:theme=""
android:requestLegacyExternalStorage="true">
I have observed this once when running the application inside the emulator. In the emulator settings, you need to specify the size of external storage ("SD Card") properly. By default, the "external storage" field is empty, and that probably means there is no such device and EACCES is thrown even if permissions are granted in the manifest.
In addition to all the answers, make sure you're not using your phone as a USB storage.
I was having the same problem on HTC Sensation on USB storage mode enabled. I can still debug/run the app, but I can't save to external storage.
My issue was with "TargetApi(23)" which is needed if your minSdkVersion is bellow 23.
So, I have request permission with the following snippet
protected boolean shouldAskPermissions() {
return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
}
#TargetApi(23)
protected void askPermissions() {
String[] permissions = {
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"
};
int requestCode = 200;
requestPermissions(permissions, requestCode);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
if (shouldAskPermissions()) {
askPermissions();
}
}
Be aware that the solution:
<application ...
android:requestLegacyExternalStorage="true" ... >
Is temporary, sooner or later your app should be migrated to use Scoped Storage.
In Android 10, you can use the suggested solution to bypass the system restrictions, but in Android 11 (R) it is mandatory to use scoped storage, and your app might break if you kept using the old logic!
This video might be a good help.
Android 10 (API 29) introduces Scoped Storage. Changing your manifest to request legacy storage is not a long-term solution.
I fixed the issue when I replaced my previous instances of Environment.getExternalStorageDirectory() (which is deprecated with API 29) with context.getExternalFilesDir(null).
Note that context.getExternalFilesDir(type) can return null if the storage location isn't available, so be sure to check that whenever you're checking if you have external permissions.
Read more here.
I'm experiencing the same. What I found is that if you go to Settings -> Application Manager -> Your App -> Permissions -> Enable Storage, it solves the issue.
It turned out, it was a stupid mistake since I had my phone still connected to the desktop PC and didn't realize this.
So I had to turn off the USB connection and everything worked fine.
I had the same problem on Samsung Galaxy Note 3, running CM 12.1. The issue for me was that i had
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18"/>
and had to use it to take and store user photos. When I tried to load those same photos in ImageLoader i got the (Permission denied) error. The solution was to explicitly add
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
since the above permission only limits the write permission up to API version 18, and with it the read permission.
In addition to all answers, if the clients are using Android 6.0, Android added new permission model for (Marshmallow).
Trick: If you are targeting version 22 or below, your application will request all permissions at install time just as it would on any device running an OS below Marshmallow. If you are trying on the emulator then from android 6.0 onwards you need to explicitly go the settings->apps-> YOURAPP -> permissions and change the permission if you have given any.
Strangely after putting a slash "/" before my newFile my problem was solved. I changed this:
File myFile= new File(Environment.getExternalStorageDirectory() + "newFile");
to this:
File myFile= new File(Environment.getExternalStorageDirectory() + "/newFile");
UPDATE:
as mentioned in the comments, the right way to do this is:
File myFile= new File(Environment.getExternalStorageDirectory(), "newFile");
I had the same problem and none of suggestions helped. But I found an interesting reason for that, on a physical device, Galaxy Tab.
When USB storage is on, external storage read and write permissions don't have any effect.
Just turn off USB storage, and with the correct permissions, you'll have the problem solved.
I would expect everything below /data to belong to "internal storage". You should, however, be able to write to /sdcard.
Change a permission property in your /system/etc/permission/platform.xml
and group need to mentioned as like below.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
<group android:gid="sdcard_rw" />
<group android:gid="media_rw" />
</uses-permission>
I had the same error when was trying to write an image in DCIM/camera folder on Galaxy S5 (android 6.0.1) and I figured out that only this folder is restricted. I simply could write into DCIM/any folder but not in camera.
This should be brand based restriction/customization.
Maybe the answer is this:
on the API >= 23 devices, if you install app (the app is not system app), you should check the storage permission in "Setting - applications", there is permission list for every app, you should check it on! try
To store a file in a directory which is foreign to the app's directory is restricted above API 29+. So to generate a new file or to create a new file use your application directory like this :-
So the correct approach is :-
val file = File(appContext.applicationInfo.dataDir + File.separator + "anyRandomFileName/")
You can write any data into this generated file !
The above file is accessible and would not throw any exception because it resides in your own developed app's directory.
The other option is android:requestLegacyExternalStorage="true" in manifest application tag as suggested by Uriel but its not a permanent solution !
When your application belongs to the system application, it can't access the SD card.
keep in mind that even if you set all the correct permissions in the manifest:
The only place 3rd party apps are allowed to write on your external card are "their own directories"
(i.e. /sdcard/Android/data/)
trying to write to anywhere else: you will get exception:
EACCES (Permission denied)
Environment.getExternalStoragePublicDirectory();
When using this deprecated method from Android 29 onwards you will receive the same error:
java.io.FileNotFoundException: open failed: EACCES (Permission denied)
Resolution here:
getExternalStoragePublicDirectory deprecated in Android Q
In my case I was using a file picker library which returned the path to external storage but it started from /root/. And even with the WRITE_EXTERNAL_STORAGE permission granted at runtime I still got error EACCES (Permission denied).
So use Environment.getExternalStorageDirectory() to get the correct path to external storage.
Example:
Cannot write: /root/storage/emulated/0/newfile.txt
Can write: /storage/emulated/0/newfile.txt
boolean externalStorageWritable = isExternalStorageWritable();
File file = new File(filePath);
boolean canWrite = file.canWrite();
boolean isFile = file.isFile();
long usableSpace = file.getUsableSpace();
Log.d(TAG, "externalStorageWritable: " + externalStorageWritable);
Log.d(TAG, "filePath: " + filePath);
Log.d(TAG, "canWrite: " + canWrite);
Log.d(TAG, "isFile: " + isFile);
Log.d(TAG, "usableSpace: " + usableSpace);
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
Output 1:
externalStorageWritable: true
filePath: /root/storage/emulated/0/newfile.txt
isFile: false
usableSpace: 0
Output 2:
externalStorageWritable: true
filePath: /storage/emulated/0/newfile.txt
isFile: true
usableSpace: 1331007488
I am creating a folder under /data/ in my init.rc (mucking around with the aosp on Nexus 7) and had exactly this problem.
It turned out that giving the folder rw (666) permission was not sufficient and it had to be rwx (777) then it all worked!
The post 6.0 enforcement of storage permissions can be bypassed if you have a rooted device via these adb commands:
root#msm8996:/ # getenforce
getenforce
Enforcing
root#msm8996:/ # setenforce 0
setenforce 0
root#msm8996:/ # getenforce
getenforce
Permissive
i faced the same error on xiaomi devices (android 10 ). The following code fixed my problem.
Libraries: Dexter(https://github.com/Karumi/Dexter) and Image picker(https://github.com/Dhaval2404/ImagePicker)
Add manifest ( android:requestLegacyExternalStorage="true")
public void showPickImageSheet(AddImageModel model) {
BottomSheetHelper.showPickImageSheet(this, new BottomSheetHelper.PickImageDialogListener() {
#Override
public void onChooseFromGalleryClicked(Dialog dialog) {
selectedImagePickerPosition = model.getPosition();
Dexter.withContext(OrderReviewActivity.this) .withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE)
.withListener(new MultiplePermissionsListener() {
#Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (report.areAllPermissionsGranted()) {
ImagePicker.with(OrderReviewActivity.this)
.galleryOnly()
.compress(512)
.maxResultSize(852,480)
.start();
}
}
#Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> list, PermissionToken permissionToken) {
permissionToken.continuePermissionRequest();
}
}).check();
dialog.dismiss();
}
#Override
public void onTakePhotoClicked(Dialog dialog) {
selectedImagePickerPosition = model.getPosition();
ImagePicker.with(OrderReviewActivity.this)
.cameraOnly()
.compress(512)
.maxResultSize(852,480)
.start();
dialog.dismiss();
}
#Override
public void onCancelButtonClicked(Dialog dialog) {
dialog.dismiss();
}
});
}
In my case the error was appearing on the line
target.createNewFile();
since I could not create a new file on the sd card,so I had to use the DocumentFile approach.
documentFile.createFile(mime, target.getName());
For the above question the problem may be solved with this approach,
fos=context.getContentResolver().openOutputStream(documentFile.getUri());
See this thread too,
How to use the new SD card access API presented for Android 5.0 (Lollipop)?
I Use the below process to handle the case with android 11 and targetapi30
As pre-created file dir as per scoped storage in my case in root dir files//<Image/Video... as per requirement>
Copy picked file and copy the file in cache directory at the time of picking from my external storage
Then at a time to upload ( on my send/upload button click) copy the file from cache dir to my scoped storage dir and then do my upload process
use this solution due to at time upload app in play store it generates warning for MANAGE_EXTERNAL_STORAGE permission and sometimes rejected from play store in my case.
Also as we used target API 30 so we can't share or forward file from our internal storage to app
2022 Kotlin way to ask permission:
private val writeStoragePermissionResult =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->}
private fun askForStoragePermission(): Boolean =
if (hasPermissions(
requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
) {
true
} else {
writeStoragePermissionResult.launch(
arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
)
)
false
}
fun hasPermissions(context: Context, vararg permissions: String): Boolean = permissions.all {
ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}

Categories

Resources