Reputation: 6582
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();
}
Upvotes: 422
Views: 661834
Reputation: 11
For API 33+ you need to request this permission to read Images
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
String[] permissionNew = new String[]{ Manifest.permission.READ_MEDIA_IMAGES};
String[] permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
private boolean checkPermissions() {
int result;
List<String> listPermissionsNeeded = new ArrayList<>();
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
for (String p : permissionsNew) {
result = ContextCompat.checkSelfPermission(requireActivity(), p);
if (result != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(p);
}
}
} else {
for (String p : permissions) {
result = ContextCompat.checkSelfPermission(requireActivity(), p);
if (result != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(p);
}
}
}
if (!listPermissionsNeeded.isEmpty()) {
requestPermissions(listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), 200);
return false;
}
return true;
}
Upvotes: 0
Reputation: 1806
If anyone is receiving this error using a hybrid app, using for example ionic, and the previous solutions did not work, first confirm that the path is valid.
If the error is coming from downloadFile or writeFile, confirm that there is not already a file in the location, it was my error.
The ionic standard library does not 'overwrite' and will throw an exception if the target file already exists, when trying to download or write. in this case the downloadFile itself tries to open and will throw EACCES exception
Solution:
If this is your problem you can save the file name with `_${Date.now()} at the end of the name or verify if the file exists and delete it before creating a new one.
Upvotes: 1
Reputation: 297
I also faced this problem and solved the problem with this method
suspend fun copyFileToInternalStorage(context: Context,uri: Uri, newDirName: String): String? {
val returnCursor = context.contentResolver.query(
uri, arrayOf(
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE
), null, null, null
)
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
val nameIndex = returnCursor!!.getColumnIndex(OpenableColumns.DISPLAY_NAME)
val sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE)
returnCursor.moveToFirst()
val name = returnCursor.getString(nameIndex)
val output: File = if (newDirName != "") {
val dir =
File(context.filesDir.toString() + "/" + newDirName)
if (!dir.exists()) {
dir.mkdir()
}
File(context.filesDir.toString() + "/" + newDirName + "/" + name)
} else {
File(context.filesDir.toString() + "/" + name)
}
try {
val inputStream =
context.contentResolver.openInputStream(uri)
val outputStream = FileOutputStream(output)
var read = 0
val bufferSize = 1024
val buffers = ByteArray(bufferSize)
while (inputStream!!.read(buffers).also { read = it } != -1) {
outputStream.write(buffers, 0, read)
}
inputStream.close()
outputStream.close()
} catch (e: java.lang.Exception) {
Log.e("Exception", e.message!!)
}
return output.path
}
Upvotes: 0
Reputation: 77
Are you getting this crash while running the junit4 test of Jetpack Macrobenchmark in a real device?
If yes then increase the version of androidx.profileinstaller:profileinstaller
.
Just click this link, find stable version and add to build.gradle(app).
For example implement(androidx.profileinstaller:profileinstaller:1.3.0)
.
I found it here: https://issuetracker.google.com/issues/203598149
Upvotes: 0
Reputation: 294
add this to manifest but this permission has a google play policy.
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
Upvotes: -2
Reputation: 101
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
}
Upvotes: 1
Reputation: 723
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();
}
});
}
Upvotes: 2
Reputation: 14622
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.
Upvotes: 421
Reputation: 668
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
Upvotes: 1
Reputation: 3057
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.
Upvotes: 29
Reputation: 12031
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");
Upvotes: 9
Reputation: 1598
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.
Upvotes: 35
Reputation: 11487
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 !
Upvotes: 6
Reputation: 1095
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">
Upvotes: 76
Reputation: 334
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
Upvotes: 4
Reputation: 1331
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)?
Upvotes: 1
Reputation: 1655
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)
Upvotes: 4
Reputation: 2319
Add gradle dependencies
implementation 'com.karumi:dexter:4.2.0'
Add below code in your main activity.
import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
checkMermission();
}
}, 4000);
}
private void checkMermission(){
Dexter.withActivity(this)
.withPermissions(
android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.INTERNET
).withListener(new MultiplePermissionsListener() {
@Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (report.isAnyPermissionPermanentlyDenied()){
checkMermission();
} else if (report.areAllPermissionsGranted()){
// copy some things
} else {
checkMermission();
}
}
@Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
token.continuePermissionRequest();
}
}).check();
}
Upvotes: 0
Reputation: 5201
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.
Upvotes: 20
Reputation: 36049
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
Upvotes: 3
Reputation: 3489
I had the same problem (API >= 23).
The solution https://stackoverflow.com/a/13569364/1729501 worked for me, but it was not practical to disconnect app for debugging.
my solution was to install proper adb device driver on Windows. The google USB driver did not work for my device.
STEP 1: Download adb drivers for your device brand.
STEP 2: Go to device manager -> other devices -> look for entries with word "adb" -> select Update driver -> give location in step 1
Upvotes: 0
Reputation: 71
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
Upvotes: 4
Reputation: 621
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();
}
}
Upvotes: 34
Reputation: 6576
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
Upvotes: 371
Reputation: 1
Add Permission in manifest.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Upvotes: -1
Reputation: 5532
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.
Upvotes: 253
Reputation: 814
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.
Upvotes: 10
Reputation: 2382
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
Upvotes: 2
Reputation: 217
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.
Upvotes: 5
Reputation: 128
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>
Upvotes: 5