I am adjusting code of my Android app (Java + native) to Android 10 Scoped Storage changes.
I declared required permissions in my manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I launched ACTION_OPEN_DOCUMENT_TREE to let the user pick a directory.
What I do is I create file on external storage, detach file desciptor and pass to native code:
DocumentFile df = documentFile.createFile("text/plain", "my_file");
ParcelFileDescriptor pfd = getApplicationContext().getContentResolver().openFileDescriptor(df.getUri(), "rw");
myNativeFunction(pfd.detachFd());
Now, native side reads/writes from/to the file. And is responsible for closing the file descriptor.
My question is how to delete that file by native code?
Normally, in order to delete file one needs to pass pathname to it (remove(), unlink() functions take it as parameter). With Uri I failed to do that - I get "No such file or directory" error.
Thank you.
Thanks to CommonsWare I realized that I need to re-think my app design.
So, for this case I decided to keep all the code operating on DocumentFile(s) at the Java side (including deletion) and read/write from/to files using read()/write() C functions at native side (using file descriptors previously detached from Java). In my case it is actually like that:
Android app:
launch ACTION_OPEN_DOCUMENT_TREE to pick document tree and pass corresponding tree Uri to my Android AAR library
request AAR library for deletion of files under tree Uri
AAR library (Java + native):
create DocumentFile object from passed tree Uri
create DocumentFile(s) under Document tree and pass file descriptors to native code (App does not have to know anything about actual files)
delete DocumentFile(s)
Related
My app is letting users select audio files with an Intent.ACTION_OPEN_DOCUMENT from within their document hierarchy (ordinarily on internal storage and not in my app's storage). The files, once selected, are then processed natively in OBOE.
I have JNI working. I can open the file in java and copy the bytecode over to native.
But if I want to open a file directly in the Native code then I must set the app to ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION. This seems a bit clumsy, it is probably because I'm sending the file path - using getPath() on the uri - to native and using fopen()?
Is it possible for me to inherit the permission from the java side to open the file natively without requiring All Files Acess permission? I tried sending a FileDescriptor over but that wasn't successful, although could have been my implementation.
In my app the user can select an existing file or just write a plain file path. Later the app uses the path to perform operations on selected file. I'm trying to study a strategy to face how filesystem access is changed in Android Q.
I see two problems:
I can't use anymore file paths or just use File interface but I need to use a Uri and I need persistent access to this Uri.
Uri are not "predicatable", i.e. if the file doesn't exist at the moment the user can't select anything and it can't guess what will be the Uri (right?)
For point one I could use ACTION_OPEN_DOCUMENT_TREE with persistent read/write on the root to have access to all files, but I have no idea how to manage point two. To be noted that the file is not created by my app but it could be created later from another app and my app just use it. How can I manage point 2?
I have a doubt I read these tutorials just to get the clear understanding of the SAF introduced in kitkat in higher version of android How to use the new SD card access API presented for Android 5.0 (Lollipop)?
How to persist permission in android API 19 (KitKat)?
Android API below 19 equivalent for ContentResolver takePersistableUriPermission
Android Gallery on KitKat returns different Uri for Intent.ACTION_GET_CONTENT
Now i have a question when the intent is fired and i get select the sd card to get the uritree from the intent which i am getting but is the root tree I will have to iterate through the uri to get the specific file uri.
Now the question is I have mp3 files in my phone and I want to edit that specific file which is selected so how can i get that selected files uri from the tree and edit it?I tried editing directly using file but it makes my mp3 file disappear and i dont want to fire SAF intent again n again so how to check is user has given permission to sd card or not?
P.S. I am using jaudio tagger for editing the tags of mp3 files.
THANK YOU!!
I have got answers of almost everything in this question Now the issue if I am using jaudio tagger library for tagging mp3 files which takes File as a objects but android 4.4 and above wont let u modify File objects so I just want to knw the alternative how can i edit File objects in 4.4 above?
This is how I did it,
first copy the file from the sdcard to the phone memory and then do the desired changes and cut and paste the file again at its original place.
Example is here where I am editing the tag of mp3 file which is in the sdcard:-
https://github.com/reyanshmishra/Rey-MusicPlayer/tree/master/app/src/main/java/com/boom/music/player/TagEditor
The library you refer to is called JaudioTagger, and it does not and most probably will never accept DocumentFile. The Storage Access Framework is Google's invention and far from any standard. And JaudioTagger is written for portability.
However, I finally managed to get JaudioTagger mostly running with SAF, but had to substantially modify it, even to rewrite some functions. Basically I replaced all File and RandomAccessFile with my own classes, and additionally the handling of temporary files and renaming must be rewritten (e.g. the scheme: copy original file, change copy, remove original file, rename copy to original name).
In fact it might be easier to use the native TagLib instead, because that already accepts a special C++ class as input. All I did was to create such C++ class whose basis is a file descriptor derived from ParcelFileDescriptor derived from Uri derived from DocumentFile.
Finally one might come to the conclusion that the Storage Access Framework is somewhat suboptimal.
I have android application which uses a lot of c++ native code. Application needs to work with files located on sdcard(read, create, append). But Kitkat+ denied writing to sdcard for 3rd party applications. Android 5 introduced new API which allows that again.
How to use the new SD card access API presented for Android 5.0 (Lollipop)?
All examples and documentation what I found are mostly for Java side. Examples for native code don't exist or are very unclear. So I want ask few questions.
The link above contains valuable example how to get DocumentFile which can return ParcelFileDescriptor. From this object I am able to receive native file descriptor - ParcelFileDescriptor.getFd(). It's integer which I am sending to c++ code through jni.
In c++ I am opening file with fdopen(fd).
My questions are :
Is fdopen function correct way how to open the file with new api? Or the DocumentFile already opens the file and I should only use fd in further operations.
It's enough to close the file descriptor inside native code with fclose? or should I close it on java side with ParcelFileDescriptor.detachFd(). Or both.
Thank you
EDIT : I getFD and detachFD works. But I never found answer how to correctly replace ftruncate, which needs write access too, and I did not found ftruncate version which takes file descriptor like a input
1) yes, use file descriptors and fdopen
2)
Open the ParcelFileDescriptor.
getFd().
Pass the Fd to native code.
Close the ParcelFileDescriptor. (this is closing your java reference)
Fd is just an int representing a linux id for a file. In native:
Fdopen
Do stuff
Fclose (note this is closing your native file pointer)
The two closes are doing different things.
Note: You still need the SAF permission for the file or a higher root.
Try Below Links:
Android - writing/saving files from native code only:
Android - writing/saving files from native code only
Android NDK Write File:
Android NDK Write File
File Operations in Android NDK:
File Operations in Android NDK
How to get FileInputStream for file in internal memory in android which is not inside applications default file directory.
I have created new directory in my application space. So openFileInput("filename") will only work for files in getFilesDir(). And openFileInput("filename") do not accept argument with path separaters "/" so I can change it to ../myfolder/.
Is there any way to get a FileInputStream on this ? ..
Note: Using normal APIs File = new File(... ) gives permission denied errors. And I have already created given Context.MODE_WORLD_WRITEABLE as the permission for my custom folder.
To make it clear :
My file is here ==> /data/data/com.app.package/app_myfolder/file1.tmp
where
"myfolder" ==> is created with Context.MODE_WORLD_WRITEABLE permissions.
I want to open FileInputStream on file1.tmp. (Normally your files are here /data/data/com.app.package/files/file1.tmp and getFilesDir() points to this directory, so also openFileInput("") takes argument which exist in same default directory.)
How to get FileInputStream for file in internal memory in android which is not inside applications default file directory.
You can't, unless the file in question is created using openFileOutput() with MODE_WORLD_READABLE, and that's not a very good idea (since any app can now read that file).
As the file was created by camera activity as a result for startActivityForResult() for MediaStore.ACTION_IMAGE_CAPTURE intent.
The camera activity should be storing the file out on external storage, not internal storage. Use the EXTRA_OUTPUT extra to indicate where the file should go.
So is there any way I can change this permissions ?
Assuming "camera activity" is referring to the one in the Android firmware, you will need to modify the firmware.