Jamie Craane
Jamie Craane

Reputation: 51

Correctly implementing openDocument for a DocumentsProvider

I am writing an example app which implements a DocumentsProvider to share files with other apps using the SAF framework. The code can be found here: DocumentsProvider example project

I have a problem sharing the selected file with for example Gmail. Depending on the method I use in openDocument (see openDocument function in example project) I get various results (see the code in the above link).

In summary:

1) When I read in the contents of a file and return

ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode))

it works from Gmail. This is using the readFilesUsingOpenDocumment() function.

2) When I read in the contents and use createReliablePipe, I can get the contents in the sample app but not in Gmail., which gives the following exception:

2020-06-10 09:15:31.643 14097-14235/nl.jcraane.myapplication E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #2 Process: nl.jcraane.myapplication, PID: 14097 Caused by: java.io.IOException: write failed: EPIPE (Broken pipe)

This is using the readFileUsingReliablePipe() function.

3) When I use createReliablePipe and I do not use a ASyncTask, the app hangs when large amounts (more than a couple of Kb) of data are transferred.

Does anyone have more insights in how openDocument should be implemented? Ideally I also want to download files via a URL and stream the bytes back when the download is finished. Is there a possibility of letting the calling app know a download is in progress (to show a progress bar)? How should createReliablePipe be used correctly?

I did look at Samba documents provider from which I have taken the ASyncTask solution but unfortunately without success.

Thanks!

Upvotes: 0

Views: 829

Answers (1)

Jamie Craane
Jamie Craane

Reputation: 51

After further investigation it seems that Dropbox for example provides its own UI for selecting a file. It does this by implementing an activity which listens to the GET_CONTENT and OPEN_DOCUMENT intent actions. I have added an example implementation of this principle to this example project: DocumentsProviderExample This way you can also show a download progress if files need to be downloaded from the network. To actually share the file the following steps must be implemented (which can al be found in the above example project):

  • Create an activity in which the user can select a file to share with another application
  • Register this activity in the manifest with intent actions GET_CONTENT and OPEN_DOCUMENT
  • Add a file provider to the manifest with a provider_paths.xml. This is needed to create a shareable url from a file
  • When the user selects a file copy this file to a path defined in provider_paths.xml, for example the application cache folder (as done in the example project)
  • Call: val uri = FileProvider.getUriForFile(this, "nl.jcraane.myapplication.provider", file) to create a content:// uri
  • Create an Intent and add the flag: Intent.FLAG_GRANT_READ_URI_PERMISSION
  • Set the uri as data on the intent and set the intent using: setResult(Activity.RESULT_OK, result)

Upvotes: 0

Related Questions