diff --git a/coil-base/src/androidTest/java/coil/map/FileUriMapperTest.kt b/coil-base/src/androidTest/java/coil/map/FileUriMapperTest.kt index cb59ac067a..e646a1cc9c 100644 --- a/coil-base/src/androidTest/java/coil/map/FileUriMapperTest.kt +++ b/coil-base/src/androidTest/java/coil/map/FileUriMapperTest.kt @@ -2,6 +2,7 @@ package coil.map import android.content.ContentResolver.SCHEME_FILE import android.content.Context +import android.net.Uri import androidx.core.net.toUri import androidx.test.core.app.ApplicationProvider import coil.request.Options @@ -52,6 +53,21 @@ class FileUriMapperTest { fun parsesPoundCharacterCorrectly() { val path = "/sdcard/fi#le.jpg" assertEquals(File(path), mapper.map(path.toUri(), Options(context))) - assertEquals(File(path), mapper.map("file://$path".toUri(), Options(context))) + } + + /** Regression test: https://github.com/coil-kt/coil/issues/1513 */ + @Test + fun ignoresAfterPathCorrectly() { + val expected = File("/sdcard/file.jpg") + val uri = Uri.parse("$SCHEME_FILE:///sdcard/file.jpg?query=value&query2=value#fragment") + assertEquals(expected, mapper.map(uri, Options(context))) + } + + /** Regression test: https://github.com/coil-kt/coil/issues/1513 */ + @Test + fun decodesEncodedPath() { + val expected = File("/sdcard/Some File.jpg") + val uri = Uri.parse("$SCHEME_FILE:///sdcard/Some%20File.jpg") + assertEquals(expected, mapper.map(uri, Options(context))) } } diff --git a/coil-base/src/main/java/coil/map/FileUriMapper.kt b/coil-base/src/main/java/coil/map/FileUriMapper.kt index 26da82bc12..22087598e2 100644 --- a/coil-base/src/main/java/coil/map/FileUriMapper.kt +++ b/coil-base/src/main/java/coil/map/FileUriMapper.kt @@ -11,8 +11,13 @@ internal class FileUriMapper : Mapper { override fun map(data: Uri, options: Options): File? { if (!isApplicable(data)) return null - val uri = if (data.scheme == null) data else data.buildUpon().scheme(null).build() - return File(uri.toString()) + if (data.scheme == SCHEME_FILE) { + return data.path?.let(::File) + } else { + // If the scheme is not "file", it's null, representing a literal path on disk. + // Assume the entire input, regardless of any reserved characters, is valid. + return File(data.toString()) + } } private fun isApplicable(data: Uri): Boolean {