0

I would like to do the following:

  • Read and edit a file that is created on the device via USB cable connected to a PC.
  • Write files that are visible when the user opens the device's internal storage in the windows file explorer.

I target Android 10 (API level 29).

The best solution I was able to find for reading files was the deprecated

val containerFile = File(
    getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
    "myFile.csv"
)
// Then I was able to read files from
val inputStream: InputStream = contentResolver.openInputStream(Uri.fromFile(containerFile))!!

This way when I placed "myFile.csv" in the downloads folder, my app was able to read the contents.

As for creating PC-readable files, the only solution I found was to create hidden temporary files, and whenever I had to make them readable from PC, I created an intent as follows:

val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
    addCategory(Intent.CATEGORY_OPENABLE)
    type = "file/csv"
    putExtra(Intent.EXTRA_TITLE, "output.csv")
    // I specify a URI for the directory that should be opened in  the system file picker
    putExtra(
        DocumentsContract.EXTRA_INITIAL_URI,
        getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
    )
}

Is there any better solution?

If not, how do I get a path to a directory which is visible from PC, using API 29?

I know this should be possible, since there are many text editor apps for android, which are doing the same things I want to, but I was not able to find any tutorial. I need a long term solution, I'm very confused... Thank you very much!

KalAnd
  • 81
  • 1
  • 7
  • Why not use `ACTION_OPEN_DOCUMENT` and `ACTION_CREATE_DOCUMENT`, and allow the user to decide where on the user's device (or in the user's cloud storage) you should put the user's content? – CommonsWare Jan 22 '21 at 15:06
  • @CommonsWare Because it is cumbersome and redundant to select the same exact folder over and over again, anytime my app decides to produce output or read input. – KalAnd Jan 22 '21 at 15:14
  • 1
    Then use `ACTION_OPEN_DOCUMENT_TREE`, to allow the user to decide where on the user's device (or in the user's cloud storage) you should put the user's content. You can use `takePersistableUriPermission()` to not need to bother the user again, and you can read and write whatever you need within that document tree. – CommonsWare Jan 22 '21 at 15:16
  • @CommonsWare Thank you very much, I'll give it a try! – KalAnd Jan 22 '21 at 15:22

1 Answers1

0

Big thanks to @CommonsWare for the suggestions!

ACTION_OPEN_DOCUMENT_TREE and GET_PERSISTABLE_PERMISSION gives acces to a user selected folder and all the files in it. Anything created by the app is visible from PC.

What I needed was

startActivityForResult(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), GET_PERSISTABLE_PERMISSION)

and

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == GET_PERSISTABLE_PERMISSION && resultCode == Activity.RESULT_OK) {
        //FileHandler.onActivityResult(data)
        data?.data?.also{ uri->
            val contentResolver = applicationContext.contentResolver
            val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
            contentResolver.takePersistableUriPermission(uri, takeFlags)

//          Write a test file in the selected folder
//            val pickedDir = DocumentFile.fromTreeUri(this, uri)
//            val tmpFile = pickedDir.createFile("text/csv", "debugTestFile")
//            val out: OutputStream? = getContentResolver().openOutputStream(tmpFile!!.uri)
//            out?.write(("\uFEFF" + "árvíztűrő tükörfúrógép\r\n").toByteArray()) // adding BOM to the start for Excel to recognize utf8
//            out?.close()
        }
    }
    super.onActivityResult(requestCode, resultCode, data)
}
KalAnd
  • 81
  • 1
  • 7