Premise
Soon I will have to update my app from android 10 to android 11.
compileSdkVersion 30
targetSdkVersion 30
I already had in the previous version
android: requestLegacyExternalStorage = "true" (Documentation says this will be ignored on android 11)
I already had in the previous version the FileProvider definition and so I left it as is.
Everything works perfectly on ANDROID 10.
Now,
From the tests carried out on the emulator (Android 11) my app is still able to create the "my custom directory" in "download / myappname" without problems even though I have the target at SDK 30... but hadn't this been prevented?
And since it allows me to do this, why then does EACCES (Permission denied) give me an error if I try to read a file which is inside the same (external) directory created by my own app?
The folder wasn't even there before, the app created it ... what's the point of preventing it from reading a static file inside it?
isn't that a contradiction?
How did you go about adapting to these limitations that I think have been adopted only in part given my practical results ... what am I missing?
Can anyone explain to me what is happening?
For example this still seems to work on Android11:
String PublicDirAccess = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();
//create new file directory object
directory = new File(PublicDirAccess + "/" + UtiGlobal.getAppTitle(MyApp.getContext()) + "/");
// if no directory exists, create new directory
if (!directory.exists())
{
directory.mkdir();
//MediaScannerConnection.scanFile(MyApp.getContext(), new String[] {directory.getAbsolutePath()}, null, null);
forceMediaScanner(MyApp.getContext(), directory);
}
But reading the documentation shouldn't work ... it shouldn't create the folder ... or not?
But then if I try to read a file inside it like this:
BufferedReader reader = new BufferedReader(new InputStreamReader(mystreamInDownloadFolder));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null)
{
sb.append(line).append("\n");
}
reader.close();
StringOut= sb.toString();
It gives me the error:
EACCES (Permission denied)
But if it makes me create the folder why then it prevents me from reading in it? ... wouldn't it have been more right that the app could continue reading in a folder created by its code? Even if it is in the external directory.
My question is simple:
Is this normal? I know very well that this should no longer be allowed but I don't understand why then the folder is created.
I add how to replicate the problem even more simply:
1) Create a folder in /storage/emulated/0/Download/Test
2) Create inside a test.txt file from the app
3) Modify the content of the file via usb PC, NETWORK or from Android using X-plore, Es-explorer, etc.
You just lost access to that file! ... so it will be impossible to transfer the files generated by my app as backups, csv, text files from one device to another? ... but is this normal?
Related
For the last 2 weeks I've been successfully converting a WPF application to a Xamarin.forms android app. Everything works as intended except for 1 thing. I've been searching the web for a few days for a solution but I can't find a working solution.
This is my current setup:
Xamarin.Froms android app
Target android version: Android 10.0
Minimum android version: Android 7.0
Xamarin.Essentials version: 1.6.0
READ_EXTERNAL_STORAGE permission
WRITE_EXTERNAL_STORAGE permission
My app should be able to open a selected file, using the Xamarin.Essientials FilePicker, Do some stuff and save the File again to the same path. The file selection is handled in the following code:
var pickresult = await FilePicker.PickAsync();
if (pickresult != null)
{
try
{
var result = await pickresult.OpenReadAsync();
var reader = new StreamReader(result);
var jsonstring = reader.ReadToEnd();
ConfigData = JsonConvert.DeserializeObject<ProjectData>(jsonstring);
PLC_Data.ProjectLoaded = true;
L_LoadedProject.Text = pickresult.FileName;
ProjectData.Filepath = pickresult.FullPath;
reader.Close();
result.Close();
//Load login page
B_Next.IsEnabled = true;
}
This is where the problem occurs. Let me clearify what happens step by step:
The FilePicker opens a File picking window.
I navigate to my preferred file in the "download" folder, could be any folder.
The file is read and converted to an object
The file path is saved
when i check the filepath i get the following string:
"/storage/emulated/0/Android/data/com.FAIS.motorconfigapp/cache/2203693cc04e0be7f4f024d5f9499e13/303bc84665374139b6303c03255e9018/config1.json"
So the FilePicker copies the "External" file to the App cache folder and returns the filepath from the Apps cache folder. When i check this folder there is indeed a copy of my selected file inside it. Reading from and writing to this file works as it should.
Now the actual question:
Why does the FilePicker copy my selected file to his cache folder and how can i prevent it?
The user should be able to select a file from anywere on the device and find the updated file in the same location.
I've checked all my settings and in my opinion everyting should be correct so i don't get why a copy is created. Does anyone have an idea?
If you need more settings, pictures, versions please ask.
Thanks in advance
I am really tired with debugging this problem. I have an application that writes to a storage. The application worked fine, until I got an update (I don't know which update caused it, because I had a break from Android development) - my Android version is 6.0.1 now.
Anyways I am trying to write to my external storage. I got prepared reading the new permission system for Android, got the permissions, and I am doing a check in my code:
checkSelfPermission("android.permission.READ_EXTERNAL_STORAGE")
checkSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE")
By debugging I've checked (I also get a code that checks and asks if permission is necessary, but I wanted to be sure that it really is ;) ) I've observed that they return value 0, which is equal to PackageManager.PERMISSION_GRANTED
So, the permissions are granted for sure. I am trying to create an App directory in the storage to write pdf files, store sqlite DB and stuff like that.
Here is how I create the directory:
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// We can read and write the media
File dir = Environment.getExternalStorageDirectory();
String sNewDir = Constants.ApplicationDataDir;
if (sSubDir == null) {
sSubDir = "";
} else {
sSubDir = sSubDir.trim();
}
if (sSubDir.length() > 0) {
sNewDir += File.separator + sSubDir;
}
File dirName = new File(dir, sNewDir);
if (!dirName.exists()) {
if (!dirName.mkdirs()) {
LogDump.e("getAppDirectory err", " (sSubDir=<" + sSubDir + "> cannot create dir: " + dirName.getAbsolutePath());
}
}
return dirName;
} else {
// Something else is wrong
LogDump.e("getAppDirectory err", " (sSubDir=<" + sSubDir + "> not mounted state: " + state);
return null;
}
The value of dirName is /storage/emulated/0/MY_APP_CONST_VALUE/sSubDir (the sSubdir is a parameter for subdirectory ie. "Preferences")
Soo, the code (checking with debugger) the execution checks that the directory does not exist, and the mkdirs() returns false result. THAT actually means that the directory does not exist, and could not be created.
During my application operation my logs get filled with:
W/FileUtils: Failed to chmod(/storage/emulated/0/MY_APP_CONST_VALUE/DB/pcdrdata.sqlite3): android.system.ErrnoException: chmod failed: EPERM (Operation not permitted)
from the SQLLite code
And FileNotFound exception for any other file operations...
This seems quite logical since It cannot create the directories, right?
Now for the most confusing part:
I am using total commander, and I can see that the directories are actually being created, the sqlite database is being copied, and all the files that do FileNotFoundException are there. I made a test, deleted them, rerun the App, and they are copied to the location once again. However any read operation on the files is not possible.
So it somehow creates the directories, allows to write (even thouh mkdirs() says otherwise) to them, but does not allow to read.
I am really confused, and tired of trying. I also tried the same without the SD card - identical results though.....
My application creates PDF files - they are created successful, but even the Total Commander says that it cannot open them....
My phone is Xperia Z3
As of KitKat you can't read from the root of the external storage anymore. You can only read in special public directories or in your own private directory on the sdcard. If you're seeing them created but not able to alter them, it seems like Android decided you could write there but not read there
I am sorry I am extremely new to android and I am lost. I successfully found out how to save a file on an android system, but every time I try to search for the file on my Android phone (which is where I have a copy of this app located) I am unable to locate it. I know it is there because the app would not start up with out it. How do you write a file that can be both used by the App AND searched by the user in the File Explorer. I am using a Galaxy Note 3 Android version 5.0 Any help would be appreciated.
private void WriteFile(String FileName, String FileCont, boolean isAppend){
File file = new File(getApplicationContext().getFilesDir().getAbsolutePath() + "/" + FileName);
try {
FileOutputStream stream = new FileOutputStream(file, isAppend);
stream.write(FileCont.getBytes());
stream.close();
}
catch(Exception ex){
}
}
Did set the permissions to write on external space in your manifest.xml?
For reference see
http://developer.android.com/reference/android/Manifest.permission.html
You have to set the "WRITE_EXTERNAL_STORAGE" permission to write on external disk. Just add the following line to your android manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
It will implicitly contain the permission to read external storage as well ;).
I don't think this is an IntelliJ issue specifically but giving all the details regardless. I created an Android Test Application in IntelliJ 13 and I'm trying to test some existing code in an Android application. This bit of code accepts an InputStream which is a JSON file to be read. I am trying to test a method for reading this file InputStream. I have the following:
My project structure looks like this:
android_test
- libs
- res
- src
- testAssetes
- file.json
And my test method is:
public void testParseFile() {
FileInputStream in = new FileInputStream(new File("./testAssets/file.json"));
// code continues..
}
I keep getting a FileNotFound exception. I've also tried the following:
android_test
- libs
- res
- src
- com
- test
- file.json
And then my code is modified to:
InputStream in = getClass().getResourceAsStream("/com/test/file.json")
And in this case, the InputStream is always null. I created a regular java project with similar code and it worked just fine. Not sure if it has something to do with how the InstrumentTestRunner is working or what the deal is.
UPDATE: I just realized that the problem is probably because these tests are running with the InstrumentationTestRunner which executes on the emulator/device. So I think what I need to know is how to get my test file on to that file system and read it in for a test.
You can specify the android_test directory as the "Working directory" in IntelliJ via "Run > Edit Configurations"
One way to do it is to use a bit of reflection. A utility method I use is :
public String assetFileContents(final String fileName) throws IOException {
StringBuilder text = new StringBuilder();
InputStream fileStream = this.getClass().getClassLoader()
.getResourceAsStream("assets/" + fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(fileStream));
String line;
while((line = reader.readLine()) != null) {
text.append(line);
}
return text.toString();
}
This return the String content of fileName. Also, I keep the test files in assets folder at /src/tests/assets (set via assets.srcDir in build.gradle, I think default has instrumentTests instead of tests)
I don't think the InstrumentTestRunner argument is relevant. As long as it's in the source path folders it should be packaged along with the app.
To see running examples using test files, see my repository here (FYI, I'm currently refactoring the project, they might have moved to another branch at a later point).
I have a question about Android programming. Basically, I am unsure of where to check where my file is, and if I wrote to it correctly. I want to locate where the file is, and I also want to know whether or not I wrote to it correctly. Below is the code I have come up with:
String lsNow = "testing";
try {
fos = openFileOutput("output.txt", Context.MODE_APPEND);
fos.write(lsNow.getBytes());
fos.close();
}
catch{
...
}
Where can I find output.txt? Might anyone know how to check this all out? if so, that would be great! I am using an emulator by the way. If I were to do this on a real Android, how would one approach this also? (Just for future reference)
You Test it in Two ways
Using File Explorer
Go to DDMS perspective--> Open File Explorer-->location of the file
Pragrammatically by using exits() method
File file = new File(context.getFilesDir(), filename);
if(file.exists())
Using openFileOutput(...) means the file will be written to internal storage on the Android device in an area which is secure from access by other apps.
If you want to make sure the file is written correctly then make sure your catch block handles any failures (if it is called then the file writing has failed).
To access the file once it has been written use openFileInput(...).