Android 6.0+ java.io.FileNotFoundException: (Permission denied) - android

Recently, I have met a really strange problem about permission issue, it confused me a few days, I hope someone will help me figure out what is going on. Thanks!
Here is the problem:
For some reason, I need to apply the storage permission for save some photos, and I had added the permission to the AndroidManifestival.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Off course, I knew I have to apply for storage permission in code after Android 6.0, and here is my code for apply for permission:
public static boolean isGrantExternalRW(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && (context.checkSelfPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
((Activity)context).requestPermissions(new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, Constants.PERMISSION_REQUEST_CODE);
return false;
}
return true;
}
I had use this method before I saved photo, and the permission dialog had shown up and I had checked it. And I had checked the app permission in the app setting, it's ok.
And here is the method I used to save the bitmap to the file:
public static String savePhotoToSDCard(Bitmap bitmap, String photoName) {
String absolutePath = "";
String state = Environment.getExternalStorageState();
Log.e("file", "---------------------" + state);
File newsDir = new File(Environment.getExternalStorageDirectory().toString()
+ File.separator + "photo");
if (!newsDir.exists()) {
newsDir.mkdirs();
}
File picFile = new File(newsDir, photoName + ".png");
absolutePath = picFile.getAbsolutePath();
if (picFile.exists()) {
picFile.delete();
}
if (photoName.equals("avatar")) {
int ratio = 2;
Bitmap result = Bitmap.createBitmap(bitmap.getWidth() / ratio, bitmap.getHeight() / ratio, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
Rect rect = new Rect(0, 0, bitmap.getWidth() / ratio, bitmap.getHeight() / ratio);
canvas.drawBitmap(bitmap, null, rect, null);
}
try {
FileOutputStream fileOutputStream = new FileOutputStream(picFile);
if (bitmap != null) {
if (bitmap.compress(Bitmap.CompressFormat.PNG, 30, fileOutputStream)) {
fileOutputStream.flush();
Log.d("Photo", "---------------------------fileOutputStream.flush");
fileOutputStream.close();
}
}
} catch (FileNotFoundException e) {
Log.e("File", "----------------------------" + e.toString());
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return absolutePath;
}
When I ran the app, it went wrong, here is the log:
java.io.FileNotFoundException: /storage/emulated/photo/avatar.png(permission denied)
But the most strange thing was that when I add the storage permission twice to AndroidManifestival.xml, it worked!
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
So, what's the problem? Please help.

Luckily, I solved my problem finally. Here was the reason:
The storage permission conflicts with the dependency below:
compile 'com.github.vungle:vungle-android-sdk:5.3.0'
When I added the dependency, system cannot recognized the storage permission which I have apply for(while I added twice in AndroidManifest.xml, it worked), but when I removed it, everything was ok ! This dependency was used to add ad into app, but now I have to abandon it.

call this method in splash screen or where you open camera .
public static boolean checkAndRequestPermissions(Context context) {
int cameraPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA);
int readfilePermission = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE);
int writefilePermission = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (cameraPermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.CAMERA);
}
if (readfilePermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
if (writefilePermission != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions((Activity) context, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
In AndroidManifestival.xml you need to add
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />

can you try like this, i think you are deleting the file as soon as you are creating it.
if (new File(newsDir, photoName + ".png").exists()) {
new File(newsDir, photoName + ".png").delete();
}
File picFile = new File(newsDir, photoName + ".png");
absolutePath = picFile.getAbsolutePath();
and in the place of
Environment.getexternalstoragedirectory().toString()
use this
Environment.getexternalstoragedirectory().getabsolutepath()

I think the solution is similar to Requesting Permissions at Run Time.
Have you handled the permissions request response?
Related to these links you have to implement these steps correctly in your code:
First: try to use this to request the permission:
boolean permissionGranted = ActivityCompat.checkSelfPermission(this, Manifest.permission......) == PackageManager.PERMISSION_GRANTED;
if(permissionGranted) {
// {Some Code}
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission....}, 200);
}
Second: implementation of OnRequestPermissionsResultCallback
...implements ActivityCompat.OnRequestPermissionsResultCallback {
Third: override onRequestPermissionsResult method
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 200: {
if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// {Some Code}
}
}
}
}

Related

Android DownloadManager java.lang.SecurityException: Unsupported path

My application works fine until I got the following error message recently:
java.lang.SecurityException: Unsupported path /storage/emulated/0/xxxzip/1234/abcde.zip
My permission in manifest file:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
And I also request run-time permission:
public boolean isStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
return true;
} else {
ActivityCompat.requestPermissions(this, new String[]{ android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
return false;
}
}
else { //permission is automatically granted on sdk<23 upon installation
return true;
}
}
The app crashes at the last line of this code:
Uri Download_Uri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(Download_Uri);
String downloadDir = savePath+"/zip/"+productId;
File direct = new File(downloadDir);
if(!direct.exists())
{
if(direct.mkdirs())
{
Log.d(TAG,"folder "+direct+" created");
}
}
int fileNamePos = url.lastIndexOf("/");
String fileName = url.substring(fileNamePos+1);
request.setDestinationUri(Uri.fromFile(new File(downloadDir + "/" + fileName)));
final long download_id = m_downloadManager.enqueue(request);
It was working previously and it's also working in simulator. Any idea?
By the way, here is the example of my download path: /storage/emulated/0/MyAppName/zip/1234. If I save to another folder like Downloads, it will be ok. So I think it's definitely the permission issue.

Unpredictable behavior while saving images into storage

TLDR: Why isn't my app asking for runtime permissions despite I have written code for it?
I am saving an image into the storage, on button click by doing something like this:
// Function triggered when save button is pressed
private void saveImage(){
// Asking Runtime permissions for API level 23 and higher
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
finallySave();
} else {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},STORAGE_WRITE_REQUEST_CODE);
}
} else {
// Do not ask permissions in the runtime for API level 22 and lower
finallySave();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == STORAGE_WRITE_REQUEST_CODE) {
if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
finallySave()
} else {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
}
}
}
private void finallySave(){
try {
File outFile = new File(imagesDir, "Abc " + System.currentTimeMillis() + ".png");
FileOutputStream outputStream = new FileOutputStream(outFile);
bitmaps[0].compress(Bitmap.CompressFormat.PNG, 100, outputStream);
outputStream.flush();
outputStream.close();
scanFile(outFile, "image/png");
} catch (Exception unused) {
}
}
The problem is, sometimes the image is not saved and the following error is shown:
java.io.FileNotFoundException: /storage/emulated/0/Abc/Abc 1601370822977.png (Permission denied)
I found out that this error is thrown when the application is not asking "storage write" permissions on the runtime. Which is the very origin of the problem that I am facing. My app is not asking for runtime permissions in some cases despite I have written the code for it. Replicating this bug is also very difficult because many times the saving operation is carried out successfully.
I am sure that my code for saving images works fine because sometimes it works (this happens when my app asks for runtime permissions) and sometimes it doesn't.
P.S: I encountered this problem when I had reinstalled my app (after uninstalling).
EDIT: imagesDir is a global variable I am assigning is as follows:
imagesDir = getImageDir(); // in onCreate
private File getImageDir() {
File directory = new File(
Environment.getExternalStorageDirectory() + "/Abc");
if (!directory.exists()) {
if (!directory.mkdirs()) {
Toast.makeText(this, "Could not create directory", Toast.LENGTH_SHORT).show();
return null;
}
}
scanFile(directory, "*/*");
return directory;
}

Permissions to write granted, but they are denied at execution time

I added the permissions to write access to the external storage device in the Manifest, and granted them in my Android phone. I even ask for them at execution time if they don't exist.
However, I always get this exception:
java.io.FileNotFoundException: /storage/emulated/03b3d97bd-5186-4506-97dc-9994b7ce0761 (Permission denied)
Do you have an idea of why?
Code
try {
if (Build.VERSION.SDK_INT >= 23) {
int permissionCheck = ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
}
OutputStream output = new FileOutputStream(Environment.getExternalStorageDirectory() + image_uuid);
byte[] buffer = new byte[1024];
int bytesRead;
BitmapDrawable bitmapDrawable = (BitmapDrawable) temp.getDrawable();
etc. etc. etc.
And in the manifest file:
</application>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
You write file in sd card before you get permission.You must wait for the result of granting permission by using below code:
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE/*1 in here*/: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted
// write file here
} else {
// permission denied
}
return;
}
// other 'case' lines to check for other
// permissions this app might request.
}
}
see here

why still get permission deny exception after granted the permission

in the mainFest it has
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
and for newer OS it checks the permission
ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
if it does not return true, it will request the permission
ActivityCompat.requestPermissions(activity, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, 5);
and only when it has the permission it will try to create the file
File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
String sysDownloadPath = directory.getPath();
try {
if (!directory.exists() && !directory.mkdirs()) {
//shouldn't happen in here
/* Checks if external storage is available for read and write */
String state = Environment.getExternalStorageState();
String externalStorageAvailable = (Environment.MEDIA_MOUNTED.equals(state)) ?
"ext-ST available" :
"ext-ST NOT available"; }
} catch (Exception e) { //<=== did not caught exception here
}
String fileName = ‘SD_20170404.pdf’;
String newFilePath = (sysDownloadPath + "/" + fileName);
File newFile = new File(newFilePath);
try {
newFile.createNewFile();// <=== throws at this one
} catch (Exception e) {
fatal Exception: java.lang.Exception: open failed: EACCES (Permission denied), newFile.getPath():/storage/emulated/0/Download/SD_20170404.pdf
It happens (not always but) with OS 5, 6 and 7. any suggestion? thanks!

Android 6.0 Write to external SD Card

I tried everything to write on external SD card on Android 6.0, but I am not able to write on it.
I did research on stackoverflow and found lot of things but none works. Here is my code
String extPath = System.getenv("SECONDARY_STORAGE") + "/Android/data/com.gvm.externalstorage.externalstoragetest/";
File file = new File(extPath,"myFiles");
if (!file.exists()) {
boolean dirResult = file.mkdirs();
Log.e("Directory Exist", dirResult + " Directory created");
} else {
Log.e("Directory Exist", "Exist");
Log.e("Direcotry Path",file.getAbsolutePath());
}
//String displayname = fileName.replace("%20", " ");
File outputFile = new File(file, "mytest5.txt");
outputFile.createNewFile();
This code works on Android 5.0 but not on Android 6.0.
Then I tried this path as well, and that gives me permission error, I have set all permission and managed code for runtime permission as well.
/mnt/media_rw/6AC9-083B
File write failed: java.io.IOException: open failed: EACCES (Permission denied)
If anyone can help me it would be great as I am trying this since last 3 days.
Thanks,
Anvesh
After long hard work I figured out a solution. In Android 6.0 it's not going to give you SD Card path always using this:
System.getenv("SECONDARY_STORAGE")
or this
Environment.getExternalStorageDirectory()
So I retrieved external SD Card path using this
File[] fs = context.getExternalFilesDirs(null);
String extPath = "";
// at index 0 you have the internal storage and at index 1 the real external...
if (fs != null && fs.length >= 2)
{
extPath = fs[1].getAbsolutePath();
Log.e("SD Path",fs[1].getAbsolutePath());
}
Rest everything will remain same for permission and all.
Thanks to those who helped me.
From API 23+(6.0) you need to request the read/write permissions even if they are already in your manifest known as Requesting Permissions at Run Time.
from docs
Beginning in Android 6.0 (API level 23), users grant permissions to
apps while the app is running, not when they install the app. This
approach streamlines the app install process, since the user does not
need to grant permissions when they install or update the app. It also
gives the user more control over the app's functionality; for example,
a user could choose to give a camera app access to the camera but not
to the device location. The user can revoke the permissions at any
time, by going to the app's Settings screen.
java
// 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" />
I think u should check your app permission first, to make sure your storage permission has been turned on.
If there's no storage permission:
Please check if u use this permission in your AndroidManifest
<uses-permission android:name="android.permission.STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
If the storage permission has been turned off:
Please check your runtime permission, maybe u can refer to this code
private void checkPermissions() {
if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return;
}
final List<String> permissionsList = new ArrayList<String>();
permissionsList.add(Manifest.permission.ACCESS_COARSE_LOCATION);
permissionsList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
permissionsList.add(Manifest.permission.WRITE_CALENDAR);
permissionsList.add(Manifest.permission.READ_PHONE_STATE);
int permissionCheckLocation = ContextCompat.checkSelfPermission(IntroductionActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);
int permissionCheckStorage = ContextCompat.checkSelfPermission(IntroductionActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
int permissionCheckCalendar = ContextCompat.checkSelfPermission(IntroductionActivity.this, Manifest.permission.WRITE_CALENDAR);
int permissionCheckPhoneState = ContextCompat.checkSelfPermission(IntroductionActivity.this, Manifest.permission.READ_PHONE_STATE);
boolean locationPermission=permissionCheckLocation == PackageManager.PERMISSION_GRANTED?true:false;
boolean storagePermission=permissionCheckStorage == PackageManager.PERMISSION_GRANTED?true:false;
boolean calendarPermission=permissionCheckCalendar == PackageManager.PERMISSION_GRANTED?true:false;
boolean phoneStatePermission=permissionCheckPhoneState == PackageManager.PERMISSION_GRANTED?true:false;
boolean shouldShowLocationPermission=ActivityCompat.shouldShowRequestPermissionRationale(IntroductionActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);
boolean shouldShowStoragePermission=ActivityCompat.shouldShowRequestPermissionRationale(IntroductionActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
boolean shouldShowCalendarPermission=ActivityCompat.shouldShowRequestPermissionRationale(IntroductionActivity.this, Manifest.permission.WRITE_CALENDAR);
boolean shouldShowPhoneStatePermission=ActivityCompat.shouldShowRequestPermissionRationale(IntroductionActivity.this, Manifest.permission.READ_PHONE_STATE);
if (permissionCheckLocation == PackageManager.PERMISSION_GRANTED && permissionCheckStorage == PackageManager.PERMISSION_GRANTED
&& permissionCheckCalendar == PackageManager.PERMISSION_GRANTED && permissionCheckPhoneState == PackageManager.PERMISSION_GRANTED){
return;
}else if(((!locationPermission&&!shouldShowLocationPermission)||(!storagePermission&&!shouldShowStoragePermission)
||(!calendarPermission&&!shouldShowCalendarPermission)||(!phoneStatePermission&&!shouldShowPhoneStatePermission))&&appContext.localCheckPermission){
showMessageOKCancel("You need to allow access these permissions",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 1);
}
});
}else{
ActivityCompat.requestPermissions(IntroductionActivity.this, permissionsList.toArray(new String[permissionsList.size()]), 0);
}
}
If still have problem, please try to change your file path :
String fileName="mytest5.txt";
File folder = new File(Environment.getExternalStorageDirectory().getPath() + "/com.gvm.externalstorage.externalstoragetest/");
if (!folder.exists()) {
try {
folder.mkdirs();
} catch (Exception e) {
e.printStackTrace();
System.out.println("Default Save Path Creation Error:" + folder);
}
}
File logFile = new File(folder, fileName);
if (!logFile.exists()) {
try {
logFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Default Save Path Creation Error:" + logFile);
}
}
Best regards. I hope this can help u
#Anvesh Another reliable method i'm using:
/**
* Get external storage path use reflect on android 6.0 device.
* Source code:
* https://github.com/android/platform_frameworks_base/blob/master/core/java/android/os/storage/StorageVolume.java
*
* #param removable the sdcard can remove or not, true means external sdcard, false means
* internal sdcard.
* #return path of sdcard we want
*/
public static String getStoragePath(boolean removable) {
WinZipApplication application = WinZipApplication.getInstance();
Context mContext = application.getApplicationContext();
StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
Class<?> storageVolumeClazz = null;
try {
storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
Method getPath = storageVolumeClazz.getMethod("getPath");
Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
Object result = getVolumeList.invoke(mStorageManager);
final int length = Array.getLength(result);
for (int i = 0; i < length; i++) {
Object storageVolumeElement = Array.get(result, i);
String path = (String) getPath.invoke(storageVolumeElement);
boolean mRemovable = (Boolean) isRemovable.invoke(storageVolumeElement);
if (removable == mRemovable) {
return path;
}
}
} catch (Exception e) {
return null;
}
return null;
}
After a lot of research I found ABSOLUTE SOLUTION. IT WORKS.
public boolean checkStorage() {
File[] fs = con.getExternalFilesDirs(null);
if (fs.length == 2)
return true;
else
return false;
}

Categories

Resources