tus-android-client icon indicating copy to clipboard operation
tus-android-client copied to clipboard

FileNotFoundException in Android 11

Open mochadwi opened this issue 3 years ago • 11 comments

https://developer.android.com/about/versions/11/behavior-changes-11

mochadwi avatar Apr 20 '21 14:04 mochadwi

removing cursor line, fixes our issue:

class TusAndroidUpload(uri: Uri, context: Context) : TusUpload() {
    init {
        val resolver = context.contentResolver


        val fd = resolver.openFileDescriptor(uri, "r") ?: throw FileNotFoundException()
        val size = fd.statSize
        try {
            fd.close()
        } catch (e: IOException) {
            Log.e("TusAndroidUpload", "unable to close ParcelFileDescriptor", e)
        }
        setSize(size)
        inputStream = resolver.openInputStream(uri)
        fingerprint = String.format("%s-%d", uri.toString(), size)
        val metadata: MutableMap<String, String> = HashMap()
        metadata["filename"] = uri.path!!
        setMetadata(metadata)
    }
}

mochadwi avatar Apr 20 '21 14:04 mochadwi

current cursor in Android 11 seems doesn't work properly and returning null instead :(

mochadwi avatar Apr 20 '21 14:04 mochadwi

Interesting report, thank you. Did you try enabling requestLegacyExternalStorage to get the behavior from Android 10 back (https://developer.android.com/about/versions/11/privacy/storage#scoped-storage)? This might be a temporary workaround until we find a solution to obtain the file name without a cursor.

Do you also have an alternative idea on how to obtain the file name?

Acconut avatar May 04 '21 10:05 Acconut

Yes the requestLegacyExternalStorage is already added, but still fails >_<

We were still not aware of how the proper workaround using cursor currently 🙏 and still use the above approach instead.

mochadwi avatar May 05 '21 07:05 mochadwi

For the filename, we're using our own Kotlin extension to get the filename from Uri. Lemme paste it here later (still afk)

mochadwi avatar May 05 '21 07:05 mochadwi

fun Uri.fileName() = "$path".substring("$path".lastIndexOf("/") + 1)

This is a hackish ways though, we assume the last index as a file name from the suffix "/".

Any better suggestions?

In Java I think it's a little bit verbose than Kotlin version

mochadwi avatar May 05 '21 07:05 mochadwi

Yes the requestLegacyExternalStorage is already added, but still fails >_<

Too bad, thanks for clarifying!

For the filename, we're using our own Kotlin extension to get the filename from Uri

I can see that this works for simple file selections, but might break when wanting to upload a file shared from another app. In this cases, the URI might be content://media/external/audio/media/710 where the last path segment does not correspond to the filename. We used the cursor to lookup the filename for this external content but apparently this is no forbidden since we are trying to access files from another app. See https://stackoverflow.com/a/27926504

I do not spend much time developing for Android these days, so I am not sure if there exists another approach for getting the filename. If not, it would be the best solution to just leave the filename empty if we get an FileNotFoundException. This way, the error is handled as gracefully as we can. Would you be interested in a PR for this?

Acconut avatar May 05 '21 08:05 Acconut

Will check the alternative ways to get the filename via cursor gracefully for Android 11 above, and then hopefully will submit the PR around end of month or early next month 🙏

mochadwi avatar May 10 '21 11:05 mochadwi

Thank you! Looking forward to your contribution :)

Acconut avatar May 11 '21 07:05 Acconut

https://twitter.com/yrezgui/status/1405194690811596808?s=19

There's a modernstorage library by Google, something to look for after the release.

Because it's a tus-android is it okay to coupled with the android-related library? 🙏

mochadwi avatar Jun 20 '21 10:06 mochadwi

There's a modernstorage library by Google, something to look for after the release.

Definitely! The modernstorage library definitely looks promising! Thanks for sharing

Because it's a tus-android is it okay to coupled with the android-related library?

Yes, exactly. tus-android-client is meant to contain Android-specific code :)

Acconut avatar Aug 10 '21 08:08 Acconut