Path): FileMetadata? { val uri = path.toUri() return when (uri.authority) { null -> fetchMetadataFromPhysicalFile(path) MediaStore.AUTHORITY -> fetchMetadataFromMediaStore(path, uri) else -> fetchMetadataFromDocumentProvider(path, uri) } } private fun fetchMetadataFromPhysicalFile(path: Path): FileMetadata? { val file = path.toFile() val isRegularFile = file.isFile val isDirectory = file.isDirectory val lastModifiedAtMillis = file.lastModified() val size = file.length() if (!isRegularFile && !isDirectory && lastModifiedAtMillis == 0L && size == 0L && !file.exists() ) { return null } val fileExtension: String = MimeTypeMap.getFileExtensionFromUrl(file.toString()) val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension.lowercase(Locale.getDefault())) val extras = mutableMapOf( Path::class to path, MetadataExtras.DisplayName::class to MetadataExtras.DisplayName(file.name), MetadataExtras.FilePath::class to MetadataExtras.FilePath(file.absolutePath), ) if (mimeType != null) extras[MetadataExtras.MimeType::class] = MetadataExtras.MimeType(mimeType) return FileMetadata( isRegularFile = isRegularFile, isDirectory = isDirectory, symlinkTarget = null, size = size, createdAtMillis = null, lastModifiedAtMillis = lastModifiedAtMillis, lastAccessedAtMillis = null, extras = extras ) } private fun fetchMetadataFromMediaStore(path: Path, uri: Uri): FileMetadata? { if (uri.pathSegments.firstOrNull().isNullOrBlank()) { return null } val isPhotoPickerUri = uri.pathSegments.firstOrNull() == "picker" val projection = if (isPhotoPickerUri) { arrayOf( MediaStore.MediaColumns.DATE_TAKEN, MediaStore.MediaColumns.DISPLAY_NAME, MediaStore.MediaColumns.MIME_TYPE, MediaStore.MediaColumns.SIZE, MediaStore.MediaColumns.DATA, ) } else { arrayOf( MediaStore.MediaColumns.DATE_ADDED, MediaStore.MediaColumns.DATE_MODIFIED, MediaStore.MediaColumns.DISPLAY_NAME, MediaStore.MediaColumns.MIME_TYPE, MediaStore.MediaColumns.SIZE, MediaStore.MediaColumns.DATA, ) } val cursor = contentResolver.query( uri, projection, null, null, null ) ?: return null cursor.use { cursor -> if (!cursor.moveToNext()) { return null } val createdTime: Long var lastModifiedTime: Long? = null if (isPhotoPickerUri) { createdTime = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_TAKEN)) } else { createdTime = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_ADDED)) lastModifiedTime = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_MODIFIED)) } val displayName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME)) val mimeType = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.MIME_TYPE)) val size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE)) val filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)) return FileMetadata( isRegularFile = true, isDirectory = false, symlinkTarget = null, size = size, createdAtMillis = createdTime, lastModifiedAtMillis = lastModifiedTime, lastAccessedAtMillis = null, extras = mapOf( Path::class to path, Uri::class to uri, MetadataExtras.DisplayName::class to MetadataExtras.DisplayName(displayName), MetadataExtras.MimeType::class to MetadataExtras.MimeType(mimeType), MetadataExtras.FilePath::class to MetadataExtras.FilePath(filePath), ) ) } } private fun fetchMetadataFromDocumentProvider(path: Path, uri: Uri): FileMetadata? { val cursor = contentResolver.query( uri, arrayOf( DocumentsContract.Document.COLUMN_LAST_MODIFIED, DocumentsContract.Document.COLUMN_DISPLAY_NAME, DocumentsContract.Document.COLUMN_MIME_TYPE, DocumentsContract.Document.COLUMN_SIZE ), null, null, null ) ?: return null cursor.use { cursor -> if (!cursor.moveToNext()) { return null } // DocumentsContract.Document.COLUMN_LAST_MODIFIED val lastModifiedTime = cursor.getLong(0) // DocumentsContract.Document.COLUMN_DISPLAY_NAME val displayName = cursor.getString(1) // DocumentsContract.Document.COLUMN_MIME_TYPE val mimeType = cursor.getString(2) // DocumentsContract.Document.COLUMN_SIZE val size = cursor.getLong(3) val isFolder = mimeType == DocumentsContract.Document.MIME_TYPE_DIR || mimeType == DocumentsContract.Root.MIME_TYPE_ITEM return FileMetadata( isRegularFile = !isFolder, isDirectory = isFolder, symlinkTarget = null, size = size, createdAtMillis = null, lastModifiedAtMillis = lastModifiedTime, lastAccessedAtMillis = null, 😱