According to "developer.android.com"
If the app targets Android 8.0 (API level 26), the system grants only READ_EXTERNAL_STORAGE at that time; however, if the app later requests WRITE_EXTERNAL_STORAGE, the system immediately grants that privilege without prompting the user.
Now, I have the READ_EXTERNAL_STORAGE and I'm requesting the DownloadManager to download a file in the Public Download folder
downloadRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, mAttachmentItem.getFilename());
Unfortunately, I got
E/UncaughtException: java.lang.IllegalStateException: Unable to create directory: /storage/emulated/0/data/user/0/com.abc.cba/files at android.app.DownloadManager$Request.setDestinationInExternalPublicDir(DownloadManager.java:699)
I have declared both of permissions in the Manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Read permission is already Granted and in Runtime I'm requesting Write permission, the system doesn't prompt any message or dialog, it's always Denied(Not Granted) in "onRequestPermissionsResult"
public static boolean isPermissionsToAccessStorageAreGranted(Context context, Activity activity) { ArrayList<String> permissions = new ArrayList<>(); if (!PermissionUtil.checkPermissions(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } if (!permissions.isEmpty()) { String[] permissionsList = permissions.toArray(new String[permissions.size()]); PermissionUtil.requestPermissions(activity, permissionsList, PermissionUtil.REQUESTCODE_ACCESS_STORAGE); return false; } else { return true; } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if(requestCode==REQUESTCODE_ACCESS_STORAGE && grantResults[0]== PackageManager.PERMISSION_GRANTED){ /* downloadFile(); */ } }
I'm trying to grant those two permissions via ADB, it shows me an error:
adb shell pm grant com.abc.cba android.permission.WRITE_EXTERNAL_STORAGE Operation not allowed: java.lang.SecurityException: Package com.abc.cbs has not requested permission android.permission.WRITE_EXTERNAL_STORAGE adb shell pm grant com.abc.cba android.permission.READ_EXTERNAL_STORAGE Operation not allowed: java.lang.SecurityException: Can't change android.permission.READ_EXTERNAL_STORAGE. It is required by the application
To read and write data to external storage, the app required WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE system permission. These permissions are added to the AndroidManifest. xml file. Add these permissions just after the package name.
When an app is granted storage permission, it can access the device storage at any time. This means it can upload personal files or even delete sensitive information from the device, so it's better to think twice before giving storage permission to untrusted apps, as it can be harmful.
Step 1) Go to Android Settings. Step 2) Depending on your device, click "Apps", "Apps & notifications", or "App permissions" and grant Keyman storage permission.
Users can see which apps have the READ_EXTERNAL_STORAGE permission in system settings. On the Settings > Privacy > Permission manager > Files and media page, each app that has the permission is listed under Allowed for all files. If your app targets Android 11, keep in mind that this access to "all files" is read-only.
Actually, It was an external problem. One of App Libs I'm using request the WRITE_EXTERNAL_PERMISSION with android:maxSdkVersion. So when merging with my Manifest it will remove the permission for the whole application.
The Solution is to add:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace"/>
You are correct in adding the permissions to the manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
For versions of Lollipop and higher, you need to also request the permissions at runtime. To solve this problem, I created a new method requestAppPermission
that I call when the main activity is created. This method runs only for Lollipop and higher, and returns early otherwise:
private void requestAppPermissions() { if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { return; } if (hasReadPermissions() && hasWritePermissions()) { return; } ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }, REQUEST_WRITE_STORAGE_REQUEST_CODE); // your request code } private boolean hasReadPermissions() { return (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED); } private boolean hasWritePermissions() { return (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED); }
I call this method in the activity's onCreate
:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Other things requestAppPermissions(); }
On first load, this will prompt the user to accept permissions.
Then, before you run any code that needs to read and write to storage, you can check these permissions, either by storing the values or running those checks again using methods hasReadPermissions()
and hasWritePermissions()
defined above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With