Android SAF

Here does not introduce the RELEVANT background of SAF, internal implementation of what, the relevant knowledge online a lot of search.

This section describes the operations related to SAF.

Other programs communicate with the SAF mainly through intents. Other applications start the SAF by calling startActivityForResult(Intent Intent, int requestCode). The SAF then returns the URI after the relevant operation is done in the SAF.

Intent.ACTION_GET_CONTENT

The Intent basically opens the SAF and lets the user select a file. The program gets the Uri of the file and can then perform any custom operations related to it.

Code:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_MIME_TYPES,
        new String[]{"application/octet-stream", "message/rfc822"});
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
Copy the code

The setType() method in the above code sets which files in the SAF are in a selectable state. */*” indicates that all files are in the selectable state. Common formats are available online.

Intent.putextra (Intent.extra_mime_types,new String[]{“application/octet-stream”, “message/rfc822”}) For example, “application/octet-stream” and “message/rfc822” are optional.

This looks like it’s just repeating the setType. But here’s the thing: if you only want certain types of files to be selectable, it’s perfectly OK to set the related type format in setType, such as setType(“message/rfc822”).

But if you want to make files in multiple formats optional, Intent.putextra (Intent.extra_miME_types,new String[]{“application/octet-stream”, “message/ rFC822 “}) If setType(“/”) is not set, the program will report a FileNotFoundException error. So the setType(“/”) is also required.

Intent.putextra (Intent.extra_ALLOW_Multiple, true) is set to allow multiple selections in the SAF.

After running the above code, we can get the URI of the user’s action in the onActivityResult(int requestCode, int resultCode, Intent Data) method.

If the user is radio, get the URI using the following code

if (data.getData() ! = null) { Uri uri = data.getData(); if (uri ! = null) { XXXXXX } }Copy the code

If the user selects multiple, the URI can be obtained using the following code

} else { ClipData clipData = data.getClipData(); if (clipData ! = null) { for (int i = 0; i < clipData.getItemCount(); i++) { ClipData.Item item = clipData.getItemAt(i); Uri uri = item.getUri(); if (uri ! = null) { XXXXXX } } }Copy the code

If (data.getData! = null) {} else {} to distinguish.

Intent.ACTION_OPEN_DOCUMENT

The Intent basically opens the SAF and lets the user select a file. The program gets the Uri of the file and can then perform any custom operations related to it.

Code:

        intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
Copy the code

ACTION_GET_CONTENT is used in the same way as intent. ACTION_GET_CONTENT and returns the same result in onActivityResult. Use data.getData() for radio, and data.getClipData() for more.

ACTION_GET_CONTENT = ACTION_GET_CONTENT

ACTION_GET_CONTENT is added at App Level 1. ACTION_OPEN_DOCUMENT was added at App Level 19. ACTION_GET_CONTENT returns ContentProvider. ACTION_OPEN_DOCUMENT returns the DocumentsProvider. ACTION_GET_CONTENT acts on a copy of a file; Intent.action_open_document returns the DocumentsProvider, so openFileDescriptor() opens the file, And use DocumentsContract. Document columns in the query details. The left side of the Intent.ACTION_GET_CONTENT file selector contains the image of the third party program. Intent.ACTION_OPEN_DOCUMENT only includes Google’s. The red box in the picture below.

Intent.ACTION_OPEN_DOCUMENT_TREE

The Intent basically opens the SAF and lets the user select a folder. The program gets the Uri of the file and can then perform any custom operations related to it.

Code:

    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
    startActivityForResult(intent, SDCARD_CHOOSE_REQUEST_CODE);
Copy the code

After running the above code, we can get the URI of the user’s action in the onActivityResult(int requestCode, int resultCode, Intent Data) method.

Get the Uri from Uri Uri = data.getData().

After obtaining the Uri, assign read and write permissions to the Uri.

getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); You can easily create subfolders or subfiles, read subfile lists, and so on.

After obtaining the Uri, we can call documentfile.fromTreeuri (@nonnull Context Context, @nonnull Uri treeUri) to create a DocumentFile object and then do the rest.

if (data.getData() ! = null) { Uri uri = data.getData(); getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); DocumentFile pickedDir = DocumentFile.fromTreeUri(context, uri); DocumentFile pickedFile = pickedDir.findFile(XXX); if (pickedFile == null) { pickedFile = pickedDir.createFile("", XXX); if (pickedFile ! = null && pickedFile.exists()) { return pickedFile.getUri(); }}Copy the code

Note: The DocumentFile class is in the Android Support or Android X package. The Android X package is recommended because Google no longer supports the Support package.

The code for importing a DocumentFile package into AndroidStudio is as follows:

Dependencies {implementation “androidx documentfile: documentfile:” 1.0.1} and if it is the source code through the android. Mk apk is compiled, the code is as follows:

LOCAL_STATIC_JAVA_LIBRARIES += androidx.documentfile_documentfile

Reference: stackoverflow.com/questions/3…