I'm trying to delete an audio file in the SD-card but I'm not successful
public boolean delete(String path)
{
return new File(path).delete();
}
While going through posts I came across Storage Access Framework but unable to understand. Is it required for deleting files from SD-card?
Moreover Can I only use Content Resolver to delete Files Like this?
getContenResolver().delete(uri,null,null);
Or is there any other method for deleting Audio?
My app is well elevated with Write permission and Read permission and I am testing on Marshmallow 6.0
Please answer.
Thanks in advance.
You need to ensure two things:
1) Since you are targeting Android.M you need to get permissions on runtime as well. Simply asking for them in the Manifest is not enough.
2) if you want to read/write data on SD card you need to use DocumentFile instead of File. The logic is more or less the same but you can refer here for more info: https://developer.android.com/reference/android/support/v4/provider/DocumentFile.html
Use this command in your OnCreate or anywhere you wish, to open a dialog that let's you select an SD directory. Select the one where your image is.
startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), 42);
Then you will need this method as is:
#Override
public void onActivityResult(int requestCode,int resultCode,Intent resultData) {
if (resultCode != RESULT_OK)
return;
Uri treeUri = resultData.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
DocumentFile YourAudioFile= pickedDir.findFile("YourAudioFileNameGoesHere");
// And here you can delete YourAudioFile or do whatever you want with it
}
Related
Is there any way to access the external SD card without using the standard SAF dialog (with ACTION_OPEN_DOCUMENT_TREE) and onActivityResult?
I know the following possibility:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, 42);
and in onActivityResult
#Override
public void onActivityResult(int requestCode, int resultCode, Intent resultData){
if(resultCode!=RESULT_OK)
return;
Uri treeUri=resultData.getData();
pickedDir= DocumentFile.fromTreeUri(getContext(), treeUri);
getContext().getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION );
// do something
// create folder, read/write files to removable sd-card, and so on
}
But this is exactly what opens the standard SAF dialog, which is (in my opinion) not user-friendly.
However, there are many file managers that allow access to the external/removable sd-card without this dialog (e.g. File Manager, RootExplorer, FX File Explorer, etc.).
This means there must be a way to bypass this default routine.
How can I realize this bypass?
I want to write on sdcard (External sdcard) on android +6.
When I use this runtime permission:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
It just works for internal storage but on sdcard i get:
java.io.IOException: Permission denied
How can other apps write on sdcard?
Thanks.
Solved
1. in android +6 the Runtime Permissions just work for Device Storage and not for Sd Card (External SD)
2.For External SD you must Use SAF (Storage Access Framwork) and select sdCard Directory
via this Code you can run SAF (Storage Access Framwork)
startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), 42);
After select the sdcrd directory the onActivityResult method was run
#Override
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode != RESULT_OK)
return;
else {
Uri treeUri = resultData.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
preferences = getSharedPreferences("MyShared" , MODE_PRIVATE) ;
SharedPreferences.Editor editor = preferences.edit() ;
editor.putString("Dir" , treeUri.toString());
editor.commit() ;
}
}
the SAF return intent of selected Directory
and we get intent data as a Intent treeUri
(Very Important)→→ for write on sd card in android 6+ you must use From DocumentFile instead of File
and DocumentFile get sd card Directory
Dont Forget to save treeUri in the SharedPreferences , Because you need to save the Directory of Sd Card and every time you need can get it from SharedPreferences
and now pickedDir is the Sdcard directory , you can use it
For API 23 and above, you need to explicitly request permission from the user AND include the uses permission tag in your android manifest: https://developer.android.com/training/permissions/requesting.html
USE this library to get permission in android phone
https://github.com/nabinbhandari/Android-Permissions
Also see this link you get possible information for the solution
Storage permission error in Marshmallow
I'm calling an intent using this:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, 42);
and selecting the root of my external SD card then taking the persisting permissions using this:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 42) {
Uri treeUri = data.getData();
this.getContentResolver().takePersistableUriPermission(treeUri, (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION));
}
}
I can write files using an outputstream to the root (my initial selection) but I can not write to any other sub folders unless I ask for permission to them again and explicitly select them.
I am not doing anything fancy right now to determine what folders I have permissions to, I'm just creating a POC and trying to write files to sub folders of a folder that I have selected and given permissions to. I get a null exception on the DocumentFile object for the destination variable below using this:
DocumentFile dir = DocumentFile.fromTreeUri(cont, Uri.parse(myUriToRoot+"/subfolder"));
DocumentFile destination = dir.createFile("image/jpeg", "myfile.jpg");
Again, if I explicitly give permission to that subfolder it works. Everything I've read says that all existing subfolders and any newly created folders underneath the folder to which you've given permissions should allow access to write files but it's not working for me.
What am I missing?
TIA
EDIT: I've also tried using the URL encoding characters for the slashes in my URI and still doesn't work unless I select the subfolder directly with another call to my intent.
I was able to resolve this by instead of setting the fromTreeUri() method to the subfolder directly, keeping that at the root and then using findFile on another DocumentFile object, then using createFile on that next DocumentFile object.
Android 5 introduce new API for working with SD-card. If you want to write files into some directory on the SC-card, y need get access to it.
As far as I know, it could be done in this way:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, 42);
and then:
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode == RESULT_OK) {
Uri treeUri = resultData.getData();
getActivity().getContentResolver().takePersistableUriPermission(treeUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
}
This code launch folder picker, and when folder is picked it requires permissions on the folder by it's Uri.
But is it possible to get permissions on exact directory by it's path? Without using folder picker. I meant that I know directory, which I want get access, and I don't want to launch Folder Picker, because it will confuse user.
How to open DocumentFile without user interaction?
It's impossible. User should choose directory using android's file picker. The only way to get access to folder is using:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, 42);
Because file is provided by Storage Access Framework DocumentsProvider. Actually it could return some Uri from 3-rd party app, which is not real file, but some entity, which 3-rd party app present as file.
My ultimate goal is to allow the user to select a folder to save a file to - the file is a video file that will be created at some point after the user has chosen the destination.
I am simply using the storage access framework picker to allow them to select a location for it to be saved in.
First of all, is there a way to allow a user to select only a folder (and not a file/filename)?
The best I can do right now is use the ACTION_CREATE_DOCUMENT Intent in order to get a save location, however I do not really want to specify the filename in the SAF picker (this will be done back in the app)...
Secondly, after reading the Storage Access Framework documentation, and cobbling together some bits from a few code samples, I've got a working DocumentsProvider which almost does what I want - which is to allow the user to browse their external storage (SD Card) directories for a suitable place to save a video file - by adding my own root which points to Environment.getExternalStorageDirectory() to the queryRoots() method.
However, what I really want is for that to be my only root (at the minute I've also got Drive, Downloads etc.).
Is it possible to remove/hide other roots so it essentially becomes an application-specific file picker?
Or even show local storage only (perhaps the Root.FLAG_LOCAL_ONLY flag can help)?
Thanks!
API 21 supports Intent.ACTION_OPEN_DOCUMENT_TREE. This allows you to select the location once and then you can use the provided URI to manipulate its content.
private static final int LOCATION_CHOOSER_REQ_CODE = 4;
public void chooseLocation() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, LOCATION_CHOOSER_REQ_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == LOCATION_CHOOSER_REQ_CODE && resultCode == Activity.RESULT_OK) {
if (data != null) {
Uri uri = data.getData(); // Use this URI to access files
}
}