Custom DocumentsProvider access to user requested intent data


#1

I am implementing a custom DocumentsProvider. When accessing the file picker using standard Android protocol, the application can provide multiple mime types they are interested in then request the file picker doing something like this:

            // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file
            // browser. It appears that many cloud providers (DropBox, etc.) don't
            // support ACTION_OPEN_DOCUMENT, and instead we must use ACTION_GET_CONTENT
            // in order for them to show up in the file picker.
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);

            // Filter to only show results that can be "opened", such as a
            // file (as opposed to a list of contacts or timezones)
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            // Use the media type they selected, 'mediaTypes' is a dropdown that allows multiple types
            // to be selected:
            ArrayList<String> l = new ArrayList<String>();
            l.add(mediaTypes.getSelectedItem().toString().toLowerCase() + "/*");
            String mimeTypes[] = new String[mediaTypes.getCount()];
            intent.putExtra(Intent.EXTRA_MIME_TYPES,l.toArray(mimeTypes));
            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

            Log.d(TAG,"Getting media types of: " + l.toString());
            intent.setType( "*/*");
            startActivityForResult(intent, GET_PATHS_CODE);

I have created a custom documents provider that allows access to local (external or internal) storage, as well as network storage for a number of providers( DropBox, etc.) that have APIs for access but have not yet built their own SAF implementation.

Question - how can my provider know what the user has requested in that intent that was used to select the file picker? I want it to understand the requested type (i.e. “video/, "image/”), then filter the file returns in a variety of ways that are also controlled by a settings dialog (i.e. “help me understand that when you say ‘image’, you mean files whose extension ends with …”).

Basically I need to know how to get that intent.putExtra data from within my DocumentsProvider class…

Thanks!


#3

how can my provider know what the user has requested in that intent that was used to select the file picker?

I don’t think that it can. I think that Android does the filtering itself. The DocumentsProvider provides the data (streams of content) and metadata (folder structure, MIME types, “display name”, etc.). AFAIK the filtering work is performed by the ACTION_OPEN_DOCUMENT activity and its supporting code.


#4

It seems very strange to me that in a custom DocumentsProvider class you have at your disposal all the freedom to select only files that match the criteria the class designer chooses (by only including in the cursor those rows that “match”), and yet as the class writer you can’t get at the intent to understand the desire of the app that requested the files…

But - ok!

T


#5

For anyone reading this post - I did validate Mark’s assumption that “filtering” (at least based on the mime types requested via the intent that launches the File Picker) is not the job of the document provider. Rather, the document provider includes the appropriate mime type of the documents it loads into the cursor via queryChildDocuments() or queryDocument() and the File Picker itself performs a filter. And the “filter” may not actually remove the documents from the File Picker list, at least in one case with a handset emulator it still showed documents that didn’t match the mime type requested, it just made them not able to be chosen in the Picker.

Tad


#6

Update: So based on my experimenting, it appears these are the rules:

One really cannot easily get access to the intent data used to launch a File Picker from within a DocumentsProvider implementation.

One must distinguish the difference between supplying values for the COLUMN_MIME_TYPES column in the cursor for queryRoots() vs. queryDocuments()/queryDocument():

queryRoots()
If a value for the column DocumentsContract.Root.COLUMN_MIME_TYPES in the cursor returned from queryRoots() is not supplied, then all root cursors supplied are shown.

If a value is supplied, then the FilePicker will only show the root if somewhere in their hierarchy the designated mime type is present. This would be the place where it would be useful to know what the app supplied as the intent to the File Picker. If the app supplies “image/*” for example in the intent that launches the File Picker, then I could supply this in that column and no root cursors that didn’t have this mime type somewhere in their hierarchy would even be shown.

queryChildDocuments()/queryDocument()
If a value for the column DocumentsContract.Document.COLUMN_MIME_TYPE is supplied, this is matched by the File Picker against the value specified in the intent. If it matches, the file can be selected in the Picker, otherwise it is shown but not allowed to be selected.


#7

Sorry that you didn’t have much luck here. DocumentsProvider is designed to support a dumb document store, with light search capability, and that’s it. It’s not really set up for your scenario.