Improve FileService API: add facility methods to deal with MessageWithAttachment object

This commit is contained in:
Benoit Marty 2020-12-08 19:31:29 +01:00
parent 62791e4b36
commit 7057b2970b
6 changed files with 76 additions and 35 deletions

View file

@ -18,8 +18,12 @@ package org.matrix.android.sdk.api.session.file
import android.net.Uri
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
import org.matrix.android.sdk.api.session.room.model.message.getFileName
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt
import org.matrix.android.sdk.internal.crypto.attachments.toElementToDecrypt
import java.io.File
/**
@ -45,19 +49,59 @@ interface FileService {
elementToDecrypt: ElementToDecrypt?,
callback: MatrixCallback<File>): Cancelable
fun isFileInCache(mxcUrl: String, mimeType: String?): Boolean
fun downloadFile(
id: String,
messageContent: MessageWithAttachmentContent,
callback: MatrixCallback<File>): Cancelable =
downloadFile(
id = id,
fileName = messageContent.getFileName(),
mimeType = messageContent.mimeType,
url = messageContent.getFileUrl(),
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt(),
callback = callback
)
fun isFileInCache(mxcUrl: String?,
mimeType: String?,
elementToDecrypt: ElementToDecrypt?
): Boolean
fun isFileInCache(messageContent: MessageWithAttachmentContent) =
isFileInCache(
mxcUrl = messageContent.getFileUrl(),
mimeType = messageContent.mimeType,
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt())
/**
* Use this URI and pass it to intent using flag Intent.FLAG_GRANT_READ_URI_PERMISSION
* (if not other app won't be able to access it)
*/
fun getTemporarySharableURI(mxcUrl: String, mimeType: String?): Uri?
fun getTemporarySharableURI(mxcUrl: String?,
mimeType: String?,
elementToDecrypt: ElementToDecrypt?): Uri?
fun getTemporarySharableURI(messageContent: MessageWithAttachmentContent): Uri? =
getTemporarySharableURI(
mxcUrl = messageContent.getFileUrl(),
mimeType = messageContent.mimeType,
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt()
)
/**
* Get information on the given file.
* Mimetype should be the same one as passed to downloadFile (limitation for now)
*/
fun fileState(mxcUrl: String, mimeType: String?): FileState
fun fileState(mxcUrl: String?,
mimeType: String?,
elementToDecrypt: ElementToDecrypt?): FileState
fun fileState(messageContent: MessageWithAttachmentContent): FileState =
fileState(
mxcUrl = messageContent.getFileUrl(),
mimeType = messageContent.mimeType,
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt()
)
/**
* Clears all the files downloaded by the service, including decrypted files

View file

@ -225,12 +225,23 @@ internal class DefaultFileService @Inject constructor(
return if (extension != null) "${url.safeFileName()}.$extension" else url.safeFileName()
}
override fun isFileInCache(mxcUrl: String, mimeType: String?): Boolean {
return File(downloadFolder, fileForUrl(mxcUrl, mimeType)).exists()
override fun isFileInCache(mxcUrl: String?, mimeType: String?, elementToDecrypt: ElementToDecrypt?): Boolean {
return fileState(mxcUrl, mimeType, elementToDecrypt) == FileService.FileState.IN_CACHE
}
override fun fileState(mxcUrl: String, mimeType: String?): FileService.FileState {
if (isFileInCache(mxcUrl, mimeType)) return FileService.FileState.IN_CACHE
private fun getClearFile(mxcUrl: String, mimeType: String?, elementToDecrypt: ElementToDecrypt?): File {
return if (elementToDecrypt == null) {
// Clear file
File(downloadFolder, fileForUrl(mxcUrl, mimeType))
} else {
// Encrypted file
File(decryptedFolder, fileForUrl(mxcUrl, mimeType))
}
}
override fun fileState(mxcUrl: String?, mimeType: String?, elementToDecrypt: ElementToDecrypt?): FileService.FileState {
mxcUrl ?: return FileService.FileState.UNKNOWN
if (getClearFile(mxcUrl, mimeType, elementToDecrypt).exists()) return FileService.FileState.IN_CACHE
val isDownloading = synchronized(ongoing) {
ongoing[mxcUrl] != null
}
@ -241,10 +252,11 @@ internal class DefaultFileService @Inject constructor(
* Use this URI and pass it to intent using flag Intent.FLAG_GRANT_READ_URI_PERMISSION
* (if not other app won't be able to access it)
*/
override fun getTemporarySharableURI(mxcUrl: String, mimeType: String?): Uri? {
override fun getTemporarySharableURI(mxcUrl: String?, mimeType: String?, elementToDecrypt: ElementToDecrypt?): Uri? {
mxcUrl ?: return null
// this string could be extracted no?
val authority = "${context.packageName}.mx-sdk.fileprovider"
val targetFile = File(downloadFolder, fileForUrl(mxcUrl, mimeType))
val targetFile = getClearFile(mxcUrl, mimeType, elementToDecrypt)
if (!targetFile.exists()) return null
return FileProvider.getUriForFile(context, authority, targetFile)
}

View file

@ -1657,10 +1657,7 @@ class RoomDetailFragment @Inject constructor(
} else if (action.messageContent is MessageWithAttachmentContent) {
session.fileService().downloadFile(
id = action.eventId,
fileName = action.messageContent.body,
mimeType = action.messageContent.mimeType,
url = action.messageContent.getFileUrl(),
elementToDecrypt = action.messageContent.encryptedFileInfo?.toElementToDecrypt(),
messageContent = action.messageContent,
callback = object : MatrixCallback<File> {
override fun onSuccess(data: File) {
if (isAdded) {
@ -1691,10 +1688,7 @@ class RoomDetailFragment @Inject constructor(
}
session.fileService().downloadFile(
id = action.eventId,
fileName = action.messageContent.body,
mimeType = action.messageContent.mimeType,
url = action.messageContent.getFileUrl(),
elementToDecrypt = action.messageContent.encryptedFileInfo?.toElementToDecrypt(),
messageContent = action.messageContent,
callback = object : MatrixCallback<File> {
override fun onSuccess(data: File) {
if (isAdded) {

View file

@ -1009,10 +1009,10 @@ class RoomDetailViewModel @AssistedInject constructor(
}
private fun handleOpenOrDownloadFile(action: RoomDetailAction.DownloadOrOpen) {
val mxcUrl = action.messageFileContent.getFileUrl()
val mxcUrl = action.messageFileContent.getFileUrl() ?: return
val isLocalSendingFile = action.senderId == session.myUserId
&& mxcUrl?.startsWith("content://") ?: false
val isDownloaded = mxcUrl?.let { session.fileService().isFileInCache(it, action.messageFileContent.mimeType) } ?: false
&& mxcUrl.startsWith("content://")
val isDownloaded = session.fileService().isFileInCache(action.messageFileContent)
if (isLocalSendingFile) {
tryOrNull { Uri.parse(mxcUrl) }?.let {
_viewEvents.post(RoomDetailViewEvents.OpenFile(
@ -1023,7 +1023,7 @@ class RoomDetailViewModel @AssistedInject constructor(
}
} else if (isDownloaded) {
// we can open it
session.fileService().getTemporarySharableURI(mxcUrl!!, action.messageFileContent.mimeType)?.let { uri ->
session.fileService().getTemporarySharableURI(action.messageFileContent)?.let { uri ->
_viewEvents.post(RoomDetailViewEvents.OpenFile(
action.messageFileContent.mimeType,
uri,
@ -1033,10 +1033,7 @@ class RoomDetailViewModel @AssistedInject constructor(
} else {
session.fileService().downloadFile(
id = action.eventId,
fileName = action.messageFileContent.getFileName(),
mimeType = action.messageFileContent.mimeType,
url = mxcUrl,
elementToDecrypt = action.messageFileContent.encryptedFileInfo?.toElementToDecrypt(),
messageContent = action.messageFileContent,
callback = object : MatrixCallback<File> {
override fun onSuccess(data: File) {
_viewEvents.post(RoomDetailViewEvents.DownloadFileState(

View file

@ -204,7 +204,7 @@ class MessageItemFactory @Inject constructor(
return MessageFileItem_()
.attributes(attributes)
.izLocalFile(fileUrl.isLocalFile())
.izDownloaded(session.fileService().isFileInCache(fileUrl, messageContent.mimeType))
.izDownloaded(session.fileService().isFileInCache(fileUrl, messageContent.mimeType, messageContent.encryptedFileInfo?.toElementToDecrypt()))
.mxcUrl(fileUrl)
.contentUploadStateTrackerBinder(contentUploadStateTrackerBinder)
.contentDownloadStateTrackerBinder(contentDownloadStateTrackerBinder)
@ -264,7 +264,7 @@ class MessageItemFactory @Inject constructor(
.attributes(attributes)
.leftGuideline(avatarSizeProvider.leftGuideline)
.izLocalFile(messageContent.getFileUrl().isLocalFile())
.izDownloaded(session.fileService().isFileInCache(mxcUrl, messageContent.mimeType))
.izDownloaded(session.fileService().isFileInCache(messageContent))
.mxcUrl(mxcUrl)
.contentUploadStateTrackerBinder(contentUploadStateTrackerBinder)
.contentDownloadStateTrackerBinder(contentDownloadStateTrackerBinder)

View file

@ -134,10 +134,7 @@ class RoomUploadsViewModel @AssistedInject constructor(
val file = awaitCallback<File> {
session.fileService().downloadFile(
id = action.uploadEvent.eventId,
fileName = action.uploadEvent.contentWithAttachmentContent.body,
url = action.uploadEvent.contentWithAttachmentContent.getFileUrl(),
mimeType = action.uploadEvent.contentWithAttachmentContent.mimeType,
elementToDecrypt = action.uploadEvent.contentWithAttachmentContent.encryptedFileInfo?.toElementToDecrypt(),
messageContent = action.uploadEvent.contentWithAttachmentContent,
callback = it
)
}
@ -154,10 +151,7 @@ class RoomUploadsViewModel @AssistedInject constructor(
val file = awaitCallback<File> {
session.fileService().downloadFile(
id = action.uploadEvent.eventId,
fileName = action.uploadEvent.contentWithAttachmentContent.body,
mimeType = action.uploadEvent.contentWithAttachmentContent.mimeType,
url = action.uploadEvent.contentWithAttachmentContent.getFileUrl(),
elementToDecrypt = action.uploadEvent.contentWithAttachmentContent.encryptedFileInfo?.toElementToDecrypt(),
messageContent = action.uploadEvent.contentWithAttachmentContent,
callback = it)
}
_viewEvents.post(RoomUploadsViewEvents.FileReadyForSaving(file, action.uploadEvent.contentWithAttachmentContent.body))