google / modernstorage

ModernStorage is a group of libraries that provide an abstraction layer over storage on Android to simplify its interactions
https://google.github.io/modernstorage/
Apache License 2.0
1.24k stars 54 forks source link

Request: add easy way to prepare a DocumentFile by file-path #15

Closed AndroidDeveloperLB closed 3 years ago

AndroidDeveloperLB commented 3 years ago

Because Google said that the current API (of DocumentFile.fromFile) doesn't provide it, and that it doesn't plan on adding such a thing either: https://issuetracker.google.com/issues/179478996#comment11

My request was that given a file-path, I should be able to reach it via DocumentFile (assuming I have access to the file, and that indeed it's a file on the device file system), and perform all operations on it like any other DocumentFile instance.

nic0lette commented 3 years ago

This library is separate from AndroidX's DocumentFile library, so this isn't something we're likely to look into soon.

What is it that you're trying to do? What does it mean to "perform all operations on it like any other DocumentFile instance"?

AndroidDeveloperLB commented 3 years ago

@nic0lette Sadly Google wrote that I should not request it for the android-x DocumentFile library : "DocumentFile isn't adding new features to the library" . If not there, and not here, I don't think there is any other library of Google to handle DocumentFile . Personally I don't get why we need more than one. :)

What I tried to do is to get DocumentFile instance (that works like any other DocumentFile) by providing a file path. As for available operations on DocumentFile, there are various basic ones, such as removal, copying, moving, getting size, check existence, get children, file creation... You can check what's possible about it here:

https://developer.android.com/reference/androidx/documentfile/provider/DocumentFile

nic0lette commented 3 years ago

This is already supported:

// Single file things
val someFile = File(filesDir, "Test.txt")
FileWriter(someFile).use { writer ->
    writer.write("Some content")
}

val docFile = DocumentFile.fromFile(someFile)
val lastModified = Date(docFile.lastModified())
Log.d(
    "docfile",
    "Name: ${docFile.name}, Size: ${docFile.length()}, Modified: $lastModified"
)

val renamed = docFile.renameTo("RenamedTest.txt")
Log.d("docfile", "Renamed? $renamed")

val renamedFile = File(filesDir, "RenamedTest.txt")
val renamedDocument = DocumentFile.fromFile(renamedFile)
Log.d("docfile", "Name: ${renamedDocument.name}")

// Directory things
val dirDocFile = DocumentFile.fromFile(filesDir)
Log.d("docfile", "List of files in ${dirDocFile.uri}:")
dirDocFile.listFiles().forEach { file ->
    Log.d("docfile", "File: ${file.name}")
}
val foundFile = dirDocFile.findFile("RenamedTest.txt")
if (foundFile?.exists() == true) {
    Log.d("docfile", "Found file: ${foundFile.name}")
}

// Clean-up
if (renamedDocument.exists()) {
    val deleted = renamedDocument.delete()
    Log.d("docfile", "Deleted? $deleted")
}
AndroidDeveloperLB commented 3 years ago

@nic0lette Google said that DocumentFile.fromFile doesn't provide it. You mean to say that it's finally available and working for all of its functions? If so, from which version of Android (or the library) ? And why Google didn't say it won't be adding such a feature yet?

You mean to say that if today I will try the sample I've reported (here: https://issuetracker.google.com/issues/162520720 ) it should now work fine?

nic0lette commented 3 years ago

I used documentfile 1.0.1 for my test. The code I wrote there works for me. (I wrote it in a simple sample and just copy + pasted it here after it ran on my Pixel running Android Pie.)

AndroidDeveloperLB commented 3 years ago

@nic0lette OK I tested again the sample. Still what you wrote is wrong. When I use listFiles on the DocumentFile of treeUri, I get a different results of on DocumentFile made from the file-path of the same place:

creating DocumentFile from path:/storage/emulated/0/b
children count of documentFileFromUri:15
children count of documentFileFromFile:0

See attached sample:

My Application.zip

Tested even on Pixel 4 with Android S beta 1.

So, the issue on the issue tracker should still exist.

nic0lette commented 3 years ago

What do you get if you use a File created at the same path and use listFiles() on it?

AndroidDeveloperLB commented 3 years ago

@nic0lette If you have storage permission (new or old) it shows the content of the folder , of course (15 files in this case). Here, updated the sample to show it too:

My Application.zip

I have found something weird though: Without permission granted (except for SAF), File API could get a single child of some random folder I've created ( "ttt" on the main storage volume). Checking further, it seems it get list only folders of the chosen path (normal files are ignored). Checking with DocumentFile.fromFile(file) , I think they both match this weird behavior.

I've decided to report this too:

https://issuetracker.google.com/issues/189965773

Please tell Google that it's wrong to have inconsistency : whether I use File API or any kind of DocumentFile, it should return to me the real content of the folder that the user has granted me access to.

But this is irrelevant . Here we talk about SAF. When you have access to some folder on the device (using SAF or storage permission), it shouldn't matter how you create the DocumentFile for it. You should be able to use it the exact same way. All functions should be available no matter how you've created the DocumentFile. It's supposed to be of a path you got access to.

Please make this library fix all this kinds of issues, and tell Google to officially fix it on Android S. Really it doesn't make sense that this API is still such a mess after all these years.

I hope you won't give me a technical explanation of why it behaves this way, because it doesn't matter : the fact is that SAF doesn't work at all like File API when it's on the file system of the device, in both functionality and performance. I've come to this library in hope it will solve it once and for all, and that newer Android versions would reduce the need for this library, hopefully removing the need completely some time in the future.