How to get access to removable sd-card without standard SAF dialog? - android

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?

Related

Delete Audio From Sdcard

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
}

No permission to subfolders to write files with DocumentFile after granting permission to root of SD Card

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.

Saving files to SD card on Android Lollipop

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.

Intent.ACTION_GET_CONTENT with Google Drive

I have the following intent:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("text/*");
startActivityForResult(intent, DBOpenHelper.REQUEST_CODE_RESTORE);
The intent allows the user to select a text file from a number of options. It works fine with local storage and Dropbox for example, and in both cases I can get the file from as follows:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if ((requestCode == DBOpenHelper.REQUEST_CODE_RESTORE)
&& (resultCode == Activity.RESULT_OK)) {
restoreFile = new File(data.getData().getPath());
restoreFileName = restoreFile.getName();
}
}
Local storage works fine and Dropbox will copy a local copy of the file to the SD card and return the correct path. The problem is that if the user to selects files from Google Drive. When they use Google Drive, data.getData().getPath() returns something like: "/document/acc=1;doc=195" instead of returning the path to the locally stored file. How do I have Google Drive download the file and return the path? I want to allow the user to select from any file storage option they have available.
Google Drive may or may not have downloaded the file locally when the user picks the file. However, in all cases, you can access the contents of the file via getContentResolver().openInputStream(data.getData()) - note that openInputStream() also supports local files and can and should be used in other cases as well.

Storage Access Framework as a "Private" (local-only) Folder/File Picker?

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
}
}

Categories

Resources