Tom
Tom

Reputation: 173

Android DocumentFile invalid URI

i am trying to list files in external storage devices on my android 5.1 phone using DocumentFile

String rootPathURI = "file:/media/storage/sdcard1/data/example.externalstorage/files/";


File f = new File(URI(rootPathURI));
DocumentFile documentFile = DocumentFile.fromFile(f);

This code works fine but i want to do it like this;

String rootPathURI = "file:/media/storage/sdcard1/data/example.externalstorage/files/";

DocumentFile documentFile = DocumentFile.fromTreeUri(getApplicationContext(), Uri.parse(rootPathURI));

but i get an exception like this:

W/System.err( 5157): java.lang.IllegalArgumentException: Invalid     URI:"file:/media/storage/sdcard1/data/example.externalstorage/files/"

Upvotes: 7

Views: 7550

Answers (2)

nnyerges
nnyerges

Reputation: 593

If you dont want to use ACTION_OPEN_DOCUMENT_TREE or ACTION_OPEN_DOCUMENT to get an Uri, you can convert FILE to Uri (SAF) using the following method valid from API19(Android4.4-Kitkat) to API28(Android8-Oreo). The returned Uri's are the same that return the dialog and its valid for API 28 security restrictions (SAF permissions), if you want to access external removable storage outside your application...

 /**
 * Ing.N.Nyerges 2019 V2.0
 *
 * Storage Access Framework(SAF) Uri's creator from File (java.IO),
 * for removable external storages
 *
 * @param context Application Context
 * @param file File path + file name
 * @return Uri[]:
 *   uri[0] = SAF TREE Uri
 *   uri[1] = SAF DOCUMENT Uri
 */
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static Uri[] getSafUris (Context context, File file) {

    Uri[] uri = new Uri[2];
    String scheme = "content";
    String authority = "com.android.externalstorage.documents";

    // Separate each element of the File path
    // File format: "/storage/XXXX-XXXX/sub-folder1/sub-folder2..../filename"
    // (XXXX-XXXX is external removable number
    String[] ele = file.getPath().split(File.separator);
    //  ele[0] = not used (empty)
    //  ele[1] = not used (storage name)
    //  ele[2] = storage number
    //  ele[3 to (n-1)] = folders
    //  ele[n] = file name

    // Construct folders strings using SAF format
    StringBuilder folders = new StringBuilder();
    if (ele.length > 4) {
        folders.append(ele[3]);
        for (int i = 4; i < ele.length - 1; ++i) folders.append("%2F").append(ele[i]);
    }

    String common = ele[2] + "%3A" + folders.toString();

    // Construct TREE Uri
    Uri.Builder builder = new Uri.Builder();
    builder.scheme(scheme);
    builder.authority(authority);
    builder.encodedPath("/tree/" + common);
    uri[0] = builder.build();

    // Construct DOCUMENT Uri
    builder = new Uri.Builder();
    builder.scheme(scheme);
    builder.authority(authority);
    if (ele.length > 4) common = common + "%2F";
    builder.encodedPath("/document/" + common + file.getName());
    uri[1] = builder.build();

    return uri;
}

You must use SAF permission to grant access to external removable storage usin something like this:

    context.grantUriPermission(context.getPackageName(), uri, Intent
            .FLAG_GRANT_READ_URI_PERMISSION | Intent
            .FLAG_GRANT_WRITE_URI_PERMISSION);
    context.getContentResolver().takePersistableUriPermission(uri, Intent
            .FLAG_GRANT_READ_URI_PERMISSION | Intent
            .FLAG_GRANT_WRITE_URI_PERMISSION);

Upvotes: 2

CommonsWare
CommonsWare

Reputation: 1006944

fromTreeUri() is for use with a Uri returned from an ACTION_OPEN_DOCUMENT_TREE request, as is noted in the documentation. It might work for a StorageVolumeUri`.

Upvotes: 3

Related Questions