How to create a content Uri for intending ACTION_OPEN_DOCUMENT_TREE

Viewed 447

I try to write an Android Instrumentation test where a user has to select a folder to save some files to. But I don't know how to create the result required for intending.

The following code is what I came up with until yet.

val testUri = Uri.parse("content://com.android.providers.downloads.documents/tree/downloads")
val openDocumentTreeResult = 
    Intent(Intent.ACTION_OPEN_DOCUMENT_TREE, testUri)

openDocumentTreeResult.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION and Intent.FLAG_GRANT_WRITE_URI_PERMISSION)

intending(hasAction(Intent.ACTION_OPEN_DOCUMENT_TREE))
    .respondWith(
        Instrumentation.ActivityResult(Activity.RESULT_OK, openDocumentTreeResult
     )
)

Of course the use of Uri.parse to create a content Uri is a bit naive. In the logs I have the following warning (probably caused by DocumentFile.fromTreeUri() using the above naive Uri):

W/DocumentFile: Failed query: java.lang.SecurityException: 
Permission Denial: opening provider com.android.providers.downloads.DownloadStorageProvider from ProcessRecord{edb1c64 4157:xyz.com.abc/u0a87} (pid=4157, uid=10087) 
requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs

and later on DocumentFile.createFile() fails by giving me a null. The corresponding code:

val treeUri = intent.data
val pickedDir = DocumentFile.fromTreeUri(this, treeUri)
val target = pickedDir.createFile(mimetype, f.name)

When I manually test this scenario first, the test runs then without error. I guess because then my app already has the permission for the downloads directory.

How do I create a result intent for intending which includes the necessary permission.

1 Answers

If you are going to return a Uri that you want DocumentFile to be able to use, the Uri has to work. It will need to point to a ContentProvider that:

  • Exists
  • Complies with the DocumentsContract API that DocumentFile will be calling (or at least the parts of it that you need for your test)
  • Returns what you want for your tests

In terms of permissions... ideally, your test provider would not require any, just to simplify matters. If that is impractical, you can try addFlags() on your Intent to grant what you need (e.g., FLAG_GRANT_READ_URI_PERMISSION), though I do not know how well that works in your Espresso test scenario.

Related