we're developping an app that will run as a service. One of the feature would be to download file at given URL (ex PDF) and save it into the download folder so user can load it from a specific application (Avenza Maps).
All the download process should be without any user interaction since it's by a service that run in the background.
i've added the following permission:
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<application
android:requestLegacyExternalStorage="true"
whatever i'll try i got the following error
java.io.FileNotFoundException: /storage/emulated/0/Download/name.pdf (Permission denied)
how can i get the permission to write on Download folder (this is system Download folder)
without having to open an activity to save the file?
i'll try multiple solution yet(2 day of google) without success
for now as stated we target API 28 (android 9)
we will later target other API since we provide the device to the client so we develop only for the API our device have.
I've recently had to develop an app that downloads voice files to a device. While you can specify permissions in the Android manifest, you must request permissions from the user. I've done so in Java, but a conversion to Kotlin should be simple.
//method is called to check the storage permissions for this app
//ensures the app can write and read files
private void checkStoragePermissions() {
Log.i("Permissions", "Checking Storage Permissions");
int writePermissionCode = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);//get current write permission
int readPermissionCode = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);//ge current read permission
Log.i("Permissions", "Fetching Read & Write Codes: " + readPermissionCode + "/" + writePermissionCode);
//if permissions to read and write to external storage is not granted
if (writePermissionCode != PackageManager.PERMISSION_GRANTED || readPermissionCode != PackageManager.PERMISSION_GRANTED) {
//request read and write permissions
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PackageManager.PERMISSION_GRANTED);
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PackageManager.PERMISSION_GRANTED);
Log.i("Permissions", "Asking For Storage Permissions");
} else {//else: if permissions to read and write is already granted
permissionsGranted = true;//set permissions granted bool to true
}
}
After you've done this the downloading of the files can be done in many ways. It's worth noting that files can't be downloaded to any location on an Android device. Only a specific destinations can be used.
I hope this helps to clear some of your confusion. Happy coding!
how can i get the permission to write on Download folder (this is system Download folder) without having to open an activity to save the file?
The simplest solution is to write somewhere else, where you do not need permissions. The methods on Context that return File objects, like getFilesDir() and getExternalFilesDir(), are your primary candidates.
Beyond that, it appears that your app is pre-installed on some device ("we provide the device to the client"). If you have developed a custom firmware image, you should be able to pre-grant the permission to your app as part of that image. Or, if the device is being distributed already configured (no first-time-power-on onboarding UI), you could manually grant WRITE_EXTERNAL_STORAGE to your app or have a UI automation script do it.
If none of those are options, then you have no choice but to ask the user for permission.
Related
Sorry, this question has probably been asked multiple times already, but I am struggling with different SDK versions. My app is used as a research instrument and solely installed per .apk directly on tablets, thus no app store. I need to record the answers from users and write them into a text file. And I am having a hard time requesting the permission from users to store the data on the external storage.
I added the following line to AndroidManifest.xml:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
In the MainActivity, I call askForPermissions in the onCreate function:
public void askForPermissions() {
int result = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (result != PackageManager.PERMISSION_GRANTED){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
startActivity(intent);
}else{
//TODO no clue, what to do here
}
}else{
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)){
Toast.makeText(this, "Permission needed to store the data. Please allow storage functionality.", Toast.LENGTH_LONG).show();
} else {
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},2);
}
}
}
createDir();
}
In API version 30, I use the "Intend" and accordingly the settings screen with the permissions shows up and I can grant writing permissions manually - and this works (directory is generated, data stored ...). First questions: In which cases can it happen that there is no external storage manager (hence the TODO)?
What I am struggling with is SDK < 30. This does not seem to work. I do not get permissions and in the app info, I cannot give the app writing permissions manually. The permissions option is disabled. What is the correct way to request permissions in that case (most preferably directly in the app)?
Sorry for the possible double post. Newbie here.
Try this in manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I'm trying to achieve some clean up tools. More and more manufacturers have forbidden rooting devices due to some "security reason", it's forbidden NOT to request for unlock.
After API 28, This code will make error:
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, 1); // Request permission or not, Will got same result
File rootFolder = Environment.getExternalStorageDirectory(); // That is working fine
rootFolder.listFiles(); // That will return null
Sure, I can use this:
android:requestLegacyExternalStorage="true"
But I belive that will be killed in future.
So, Any elegant way to manage SDCard?
On Android 10 Environment.getExternalStorageDirectory() and Environment.getExternalStoragePublicDirectory() will return storage paths but paths are not readable or writable.
For Android 10 you can continue to use paths provided by Environment.getExternalStorageDirectory() and Environment.getExternalStoragePublicDirectory() if you add android:requestLegacyExternalStorage="true" to application tag in manifest file. At runtime your app can call Environment.isExternalStorageLegacy() to check if the request has been done.
Another (not known) possibility (only for Android 10) is to add <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> to manifest file.
The user has to go to the advanced settings of the app and enable from Advanced settings Install unknown apps | Allow from this source.
The nice thing with this is that the user can switch the access rights. You can make it easier for the user if you implement an intent for
Settings.ACTION_APPLICATION_DETAILS_SETTINGS where he can change the settings.
A funny thing is that Environment.isExternalStorageLegacy() returns true then too.
Compiling for Android 11 both options do not work on an Android 11 device. (But they continue to work for Android 10 devices). The paths of Environment.getExternalStorageDirectory() and Environment.getExternalStoragePublicDirectory() are usable again in read mode and very often in write mode too. And this is great as one can simply list the contents of directories like Download or Pictures or DCIM/Camera again using the File class.
But adding <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> to manifest file and implementing an intent for
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION will give your app read/write access for all files even on removable micro sd card.
(Finally you can remove the google ban not being able to read/write your own micro sd card on your own Android device using your own app).
Environment.isExternalStorageManager() can be used to check if the permission is on/off.
As long as you do not try to upload your app to the play store you are fine.
use android:requestLegacyExternalStorage="true" in your Manifest below <application
I test my application on a virtual nexus 5 with Marshmallow
I got a notification about a virtual sd card being ready and I tried choosing both internal and external storage.
I uploaded a text file to sdcard/Download by dragging and dropping to the emulator.
I added <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> and even <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> to my manifest.
When I try to read a file a sd card using code such as this
File sdcard = Environment.getExternalStorageDirectory();
File file = new File(sdcard,"Download/gradle.build");
try {
BufferedReader br = new BufferedReader(new FileReader(file))
...}
I get an open failed... EACCESS - permission denied exception thrown.
Why can't I read a file from the sdcard? Thanks.
Request permission at runtime is a feature added in android version 6.0 The idea is when the app is installed customers just grant permission without knowing the security risk. Dangerous permission must be granted at runtime so hopefully users know the risk, in this case you want to use SD storage because (give reason here). Good luck.
Since you are targetting devices marshmallow or above you have to give permissions at runtime and permissions declared in manifest does not mean anything. So have to give permission like below before accessing any of the file related read or write.
first check if permission already given by checking this
// Assume this Activity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permissionCheck==PackageManager.PERMISSION_GRANTED){
//this means permission is granted and you can do read and write
}else{
requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_PERMISSION);
}
here is permission guide
I'm testing my app on an emulator. I have an export function where I create and write to a file in the external storage's downloads directory. And I also have an import function where I read a file from the external storage's downloads directory.
From Android documentation:
If the device is running Android 5.1 or lower, or your app's target SDK is 22 or lower: If you list a dangerous permission in your manifest, the user has to grant the permission when they install the app; if they do not grant the permission, the system does not install the app at all.
If the device is running Android 6.0 or higher, and your app's target SDK is 23 or higher: The app has to list the permissions in the manifest, and it must request each dangerous permission it needs while the app is running. The user can grant or deny each permission, and the app can continue to run with limited capabilities even if the user denies a permission request.
My emulator is running on Android 6.0 and my app's target SDK is 25, therefore I must also request each dangerous permission it needs while the app is running. I did so for the export functionality and everything works properly. However, when I'm implementing the import function I didn't request a permission during runtime. And the strange thing is I'm still able to read from my external storage's permission without READ_EXTERNAL_STORAGE being requested and granted at runtime. READ_EXTERNAL_STORAGE is a dangerous permission according to this Android documentation .
To verify, I made sure to disable permissions before I started using the feature and after it is completed, I verified again that the permission still wasn't granted. Although I'm happy with the behaviour since it's working without me requesting permission at runtime, but according to the documentations I don't believe this behaviour is expected. That's why I will like to know what's causing this and to figure out the problem before I publish any changes for the app.
Here's a code snippet of my manifest:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
The code snippet where I pick a file to read:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("text/*");
startActivityForResult(intent, GET_FILE_RESULT_CODE);
The code snippet where I read the file chosen from the code snippet above (exportFile is simply the URI from onActivityResult):
BufferedReader br;
try {
br = new BufferedReader(new InputStreamReader(context.getContentResolver().openInputStream(exportFile)));
String line;
// Skip first header line
br.readLine();
while ((line = br.readLine()) != null) {...}
Thanks!
There's a well explanation here,
READ_EXTERNAL_STORAGE
Provides protected read access to external storage. In Android 4.1 by
default all applications still have read access. This will be changed
in a future release to require that applications explicitly request
read access using this permission. If your application already
requests write access, it will automatically get read access as well.
There is a new developer option to turn on read access restriction,
for developers to test their applications against how Android will
behave in the future.
In short, READ_EXTERNAL_STORAGE only exists as of Jelly Bean (Level 16). So, unless you're using a Jelly Bean phone and set the developer option "Protect USB storage" it won't be a problem.
You know,Android Runtime Permissions are grouped, since you applied for WRITE_EXTERNAL_STORAGE permission in the manifest already, so there's no need to apply for READ_EXTERNAL_STORAGE permissions.Both of them are the same group.
Before I begin explaining my question, I have to mention that I am new to Android development.
I am trying to write a program for Android which uses OpenCV's Java API for some data processing. I am developing unit tests for classes that implement algorithms and these classes are not related to any activity yet. In other words, I just want to test the functionality of methods before dealing with activities.
Because I need to have access to OpenCV libraries, I have written my unit test under androidTest in Android Studio. The files that contain data and need to be read in the program are copied to /sdcard/DIR and /storage/emulated/0/DIR. I have added the following permission to AndroidManifest.xml to grant access to external storage.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
However, when I try to read files from external storage I get
open failed: EACCES (Permission denied). Note that I concatenate the path returned by Environment.getExternalStorageDirectory().getAbsolutePath() with the name of data files and use a FileInputStream later on to read contents of the files.
I have seen similar questions and answers that mention access should be granted at runtime for APIs above 23. But because I don't have any activities for my methods, I guess I can't request permission at runtime.
Are there any other directories I can use to place my data files that do not require these permissions? I thought of assets as an option, but I am assuming that assets are put in the final apk and if I need to change files for a different data, I have to create a new apk every time.
How should I grant access to /sdcard without having any activity that asks user for a permission at runtime?
Can I do local testing instead of androidTest by installing OpenCV libraries on my linux machine?
Sorry but android doesn't provide that type of access
you will need to create a activity to launch the application
I think if you are using marshmallow device then you will be needing to ask the permission to read and write external storage at runtime
you can refer at the following liink
https://developer.android.com/training/permissions/requesting.html
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)==
PackageManager.PERMISSION_GRANTED) {
//do the things} else {
requestPermissions(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE },
AnyNumber);
Later catch those requests in
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == AnyNumber) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
}
}
}
I found a temporary workaround for this issue. I designed a button in MainActivity that when pressed, asks user for permission to access the directory where my files are located at. Afterwards, I could run the androidTest unit tests without facing the exception because this permission needs to be granted only once.