diff --git a/changelog.d/1991.misc b/changelog.d/1991.misc new file mode 100644 index 0000000000..05a0367bed --- /dev/null +++ b/changelog.d/1991.misc @@ -0,0 +1 @@ +Render images in Notification diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessageMediaRepo.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessageMediaRepo.kt index cc8bd1945f..62ddc4845b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessageMediaRepo.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/VoiceMessageMediaRepo.kt @@ -24,6 +24,7 @@ import io.element.android.libraries.di.CacheDirectory import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.matrix.api.mxc.MxcTools import java.io.File /** @@ -66,6 +67,7 @@ interface VoiceMessageMediaRepo { class DefaultVoiceMessageMediaRepo @AssistedInject constructor( @CacheDirectory private val cacheDir: File, + mxcTools: MxcTools, private val matrixMediaLoader: MatrixMediaLoader, @Assisted private val mediaSource: MediaSource, @Assisted("mimeType") private val mimeType: String?, @@ -101,7 +103,7 @@ class DefaultVoiceMessageMediaRepo @AssistedInject constructor( } } - private val cachedFile: File? = mxcUri2FilePath(mediaSource.url)?.let { + private val cachedFile: File? = mxcTools.mxcUri2FilePath(mediaSource.url)?.let { File("${cacheDir.path}/$CACHE_VOICE_SUBDIR/$it") } } @@ -110,24 +112,3 @@ class DefaultVoiceMessageMediaRepo @AssistedInject constructor( * Subdirectory of the application's cache directory where voice messages are stored. */ private const val CACHE_VOICE_SUBDIR = "temp/voice" - -/** - * Regex to match a Matrix Content (mxc://) URI. - * - * See: https://spec.matrix.org/v1.8/client-server-api/#matrix-content-mxc-uris - */ -private val mxcRegex = Regex("""^mxc:\/\/([^\/]+)\/([^\/]+)$""") - -/** - * Sanitizes an mxcUri to be used as a relative file path. - * - * @param mxcUri the Matrix Content (mxc://) URI of the voice message. - * @return the relative file path as "/" or null if the mxcUri is invalid. - */ -private fun mxcUri2FilePath(mxcUri: String): String? = mxcRegex.matchEntire(mxcUri)?.let { match -> - buildString { - append(match.groupValues[1]) - append("/") - append(match.groupValues[2]) - } -} diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/DefaultVoiceMessageMediaRepoTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/DefaultVoiceMessageMediaRepoTest.kt index 0a62d6ca91..0208d06e95 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/DefaultVoiceMessageMediaRepoTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/timeline/DefaultVoiceMessageMediaRepoTest.kt @@ -20,6 +20,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.matrix.api.mxc.MxcTools import io.element.android.libraries.matrix.test.media.FakeMediaLoader import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -139,6 +140,7 @@ private fun createDefaultVoiceMessageMediaRepo( mxcUri: String = MXC_URI, ) = DefaultVoiceMessageMediaRepo( cacheDir = temporaryFolder.root, + mxcTools = MxcTools(), matrixMediaLoader = matrixMediaLoader, mediaSource = MediaSource( url = mxcUri, diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/mxc/MxcTools.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/mxc/MxcTools.kt new file mode 100644 index 0000000000..43a78d1d23 --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/mxc/MxcTools.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.api.mxc + +import javax.inject.Inject + +class MxcTools @Inject constructor() { + /** + * Regex to match a Matrix Content (mxc://) URI. + * + * See: https://spec.matrix.org/v1.8/client-server-api/#matrix-content-mxc-uris + */ + private val mxcRegex = Regex("""^mxc://([^/]+)/([^/]+)$""") + + /** + * Sanitizes an mxcUri to be used as a relative file path. + * + * @param mxcUri the Matrix Content (mxc://) URI of the file. + * @return the relative file path as "/" or null if the mxcUri is invalid. + */ + fun mxcUri2FilePath(mxcUri: String): String? = mxcRegex.matchEntire(mxcUri)?.let { match -> + buildString { + append(match.groupValues[1]) + append("/") + append(match.groupValues[2]) + } + } +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt index 08f40c3376..8275b8ee5f 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt @@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.MessageType data class NotificationData( val eventId: EventId, val roomId: RoomId, + // mxc url val senderAvatarUrl: String?, val senderDisplayName: String?, val roomAvatarUrl: String?, @@ -34,8 +35,6 @@ data class NotificationData( val isNoisy: Boolean, val timestamp: Long, val content: NotificationContent, - // For images for instance - val contentUrl: String?, val hasMention: Boolean, ) diff --git a/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/mxc/MxcToolsTest.kt b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/mxc/MxcToolsTest.kt new file mode 100644 index 0000000000..652b5a6de6 --- /dev/null +++ b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/mxc/MxcToolsTest.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.api.mxc + +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +class MxcToolsTest { + @Test + fun `mxcUri2FilePath returns extracted path`() { + val mxcTools = MxcTools() + val mxcUri = "mxc://server.org/abc123" + val filePath = mxcTools.mxcUri2FilePath(mxcUri) + assertThat(filePath).isEqualTo("server.org/abc123") + } + + @Test + fun `mxcUri2FilePath returns null for invalid data`() { + val mxcTools = MxcTools() + assertThat(mxcTools.mxcUri2FilePath("")).isNull() + assertThat(mxcTools.mxcUri2FilePath("mxc://server.org")).isNull() + assertThat(mxcTools.mxcUri2FilePath("mxc://server.org/")).isNull() + assertThat(mxcTools.mxcUri2FilePath("m://server.org/abc123")).isNull() + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/NotificationMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/NotificationMapper.kt index 9914a66c85..6285ba393f 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/NotificationMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/NotificationMapper.kt @@ -52,7 +52,6 @@ class NotificationMapper( isNoisy = item.isNoisy.orFalse(), timestamp = item.timestamp() ?: clock.epochMillis(), content = item.event.use { notificationContentMapper.map(it) }, - contentUrl = null, hasMention = item.hasMention.orFalse(), ) } diff --git a/libraries/push/impl/src/main/AndroidManifest.xml b/libraries/push/impl/src/main/AndroidManifest.xml index 6085ffe4a4..17bd098f90 100644 --- a/libraries/push/impl/src/main/AndroidManifest.xml +++ b/libraries/push/impl/src/main/AndroidManifest.xml @@ -15,6 +15,7 @@ --> + + + + + + + diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolver.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolver.kt index 26c8a7d55b..017627305e 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolver.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolver.kt @@ -16,7 +16,12 @@ package io.element.android.libraries.push.impl.notifications +import android.content.Context +import android.net.Uri +import androidx.core.content.FileProvider import io.element.android.libraries.core.log.logger.LoggerTag +import io.element.android.libraries.di.ApplicationContext +import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClientProvider import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId @@ -60,6 +65,8 @@ class NotifiableEventResolver @Inject constructor( private val stringProvider: StringProvider, private val clock: SystemClock, private val matrixClientProvider: MatrixClientProvider, + private val notificationMediaRepoFactory: NotificationMediaRepo.Factory, + @ApplicationContext private val context: Context, ) { suspend fun resolveEvent(sessionId: SessionId, roomId: RoomId, eventId: EventId): NotifiableEvent? { @@ -75,10 +82,13 @@ class NotifiableEventResolver @Inject constructor( }.getOrNull() // TODO this notificationData is not always valid at the moment, sometimes the Rust SDK can't fetch the matching event - return notificationData?.asNotifiableEvent(sessionId) + return notificationData?.asNotifiableEvent(client, sessionId) } - private fun NotificationData.asNotifiableEvent(userId: SessionId): NotifiableEvent? { + private suspend fun NotificationData.asNotifiableEvent( + client: MatrixClient, + userId: SessionId, + ): NotifiableEvent? { return when (val content = this.content) { is NotificationContent.MessageLike.RoomMessage -> { val messageBody = descriptionFromMessageContent(content, senderDisplayName ?: content.senderId.value) @@ -96,7 +106,7 @@ class NotifiableEventResolver @Inject constructor( timestamp = this.timestamp, senderName = senderDisplayName, body = notificationBody, - imageUriString = this.contentUrl, + imageUriString = fetchImageIfPresent(client)?.toString(), roomName = roomDisplayName, roomIsDirect = isDirect, roomAvatarPath = roomAvatarUrl, @@ -238,6 +248,34 @@ class NotifiableEventResolver @Inject constructor( stringProvider.getString(R.string.notification_room_invite_body) } } + + private suspend fun NotificationData.fetchImageIfPresent(client: MatrixClient): Uri? { + val fileResult = when (val content = this.content) { + is NotificationContent.MessageLike.RoomMessage -> { + when (val messageType = content.messageType) { + is ImageMessageType -> notificationMediaRepoFactory.create(client) + .getMediaFile( + mediaSource = messageType.source, + mimeType = messageType.info?.mimetype, + body = messageType.body, + ) + is VideoMessageType -> null // Use the thumbnail here? + else -> null + } + } + else -> null + } ?: return null + + return fileResult + .onFailure { + Timber.tag(loggerTag.value).e(it, "Failed to download image for notification") + } + .map { mediaFile -> + val authority = "${context.packageName}.notifications.fileprovider" + FileProvider.getUriForFile(context, authority, mediaFile) + } + .getOrNull() + } } @Suppress("LongParameterList") diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationMediaRepo.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationMediaRepo.kt new file mode 100644 index 0000000000..505a4f4a3c --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationMediaRepo.kt @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.push.impl.notifications + +import com.squareup.anvil.annotations.ContributesBinding +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.CacheDirectory +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.matrix.api.mxc.MxcTools +import java.io.File + +/** + * Fetches the media file for a notification. + * + * Media is downloaded from the rust sdk and stored in the application's cache directory. + * Media files are indexed by their Matrix Content (mxc://) URI and considered immutable. + * Whenever a given mxc is found in the cache, it is returned immediately. + */ +interface NotificationMediaRepo { + + /** + * Factory for [NotificationMediaRepo]. + */ + fun interface Factory { + /** + * Creates a [NotificationMediaRepo]. + * + */ + fun create( + client: MatrixClient + ): NotificationMediaRepo + } + + /** + * Returns the file. + * + * In case of a cache hit the file is returned immediately. + * In case of a cache miss the file is downloaded and then returned. + * + * @param mediaSource the media source of the media. + * @param mimeType the mime type of the media. + * @param body the body of the message. + * @return A [Result] holding either the media [File] from the cache directory or an [Exception]. + */ + suspend fun getMediaFile( + mediaSource: MediaSource, + mimeType: String?, + body: String?, + ): Result +} + +class DefaultNotificationMediaRepo @AssistedInject constructor( + @CacheDirectory private val cacheDir: File, + private val mxcTools: MxcTools, + @Assisted private val client: MatrixClient, +) : NotificationMediaRepo { + + @ContributesBinding(AppScope::class) + @AssistedFactory + fun interface Factory : NotificationMediaRepo.Factory { + override fun create( + client: MatrixClient, + ): DefaultNotificationMediaRepo + } + + private val matrixMediaLoader = client.mediaLoader + + override suspend fun getMediaFile( + mediaSource: MediaSource, + mimeType: String?, + body: String?, + ): Result { + val cachedFile = mediaSource.cachedFile() + return when { + cachedFile == null -> Result.failure(IllegalStateException("Invalid mxcUri.")) + cachedFile.exists() -> Result.success(cachedFile) + else -> matrixMediaLoader.downloadMediaFile( + source = mediaSource, + mimeType = mimeType, + body = body, + ).mapCatching { + it.use { mediaFile -> + val dest = cachedFile.apply { parentFile?.mkdirs() } + if (mediaFile.persist(dest.path)) { + dest + } else { + error("Failed to move file to cache.") + } + } + } + } + } + + private fun MediaSource.cachedFile(): File? = mxcTools.mxcUri2FilePath(url)?.let { + File("${cacheDir.path}/$CACHE_NOTIFICATION_SUBDIR/$it") + } +} + +/** + * Subdirectory of the application's cache directory where file are stored. + */ +private const val CACHE_NOTIFICATION_SUBDIR = "temp/notif" diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationsFileProvider.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationsFileProvider.kt new file mode 100644 index 0000000000..11999207ed --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationsFileProvider.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.push.impl.notifications + +import androidx.core.content.FileProvider + +/** + * We have to declare our own file provider to avoid collision with other modules + * having their own. + */ +class NotificationsFileProvider : FileProvider() diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/TestNotificationReceiver.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/TestNotificationReceiver.kt index a7135cee74..ec2cd227ca 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/TestNotificationReceiver.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/TestNotificationReceiver.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 New Vector Ltd + * Copyright (c) 2023 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/model/NotifiableMessageEvent.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/model/NotifiableMessageEvent.kt index 1b6bb8a67a..4b30bbe86d 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/model/NotifiableMessageEvent.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/model/NotifiableMessageEvent.kt @@ -58,9 +58,8 @@ data class NotifiableMessageEvent( override val description: String = body ?: "" val title: String = senderName ?: "" - // TODO EAx The image has to be downloaded and expose using the file provider. - // Example of value from Element Android: - // content://im.vector.app.debug.mx-sdk.fileprovider/downloads/downloads/816abf76d806c768760568952b1862c8/F/72c33edd23dee3b95f4d5a18aa25fa54/image.png + // Example of value: + // content://io.element.android.x.debug.notifications.fileprovider/downloads/temp/notif/matrix.org/XGItzSDOnSyXjYtOPfiKexDJ val imageUri: Uri? get() = imageUriString?.let { Uri.parse(it) } } diff --git a/libraries/push/impl/src/main/res/xml/notifications_provider_paths.xml b/libraries/push/impl/src/main/res/xml/notifications_provider_paths.xml new file mode 100644 index 0000000000..7c15e41df3 --- /dev/null +++ b/libraries/push/impl/src/main/res/xml/notifications_provider_paths.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolverTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolverTest.kt index 6276983cc9..bad49b64ef 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolverTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolverTest.kt @@ -42,6 +42,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClientProvider import io.element.android.libraries.matrix.test.notification.FakeNotificationService +import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationMediaRepo import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent @@ -257,7 +258,7 @@ class NotifiableEventResolverTest { createNotificationData( content = NotificationContent.MessageLike.RoomMessage( senderId = A_USER_ID_2, - messageType = LocationMessageType("Location", "geo:1,2", null), + messageType = LocationMessageType("Location", "geo:1,2", null), ) ) ) @@ -274,7 +275,7 @@ class NotifiableEventResolverTest { createNotificationData( content = NotificationContent.MessageLike.RoomMessage( senderId = A_USER_ID_2, - messageType = NoticeMessageType("Notice", null), + messageType = NoticeMessageType("Notice", null), ) ) ) @@ -291,7 +292,7 @@ class NotifiableEventResolverTest { createNotificationData( content = NotificationContent.MessageLike.RoomMessage( senderId = A_USER_ID_2, - messageType = EmoteMessageType("is happy", null), + messageType = EmoteMessageType("is happy", null), ) ) ) @@ -487,11 +488,15 @@ class NotifiableEventResolverTest { Result.success(FakeMatrixClient(notificationService = notificationService)) } }) - + val notificationMediaRepoFactory = NotificationMediaRepo.Factory { + FakeNotificationMediaRepo() + } return NotifiableEventResolver( stringProvider = AndroidStringProvider(context.resources), clock = FakeSystemClock(), matrixClientProvider = matrixClientProvider, + notificationMediaRepoFactory = notificationMediaRepoFactory, + context = context, ) } @@ -512,7 +517,6 @@ class NotifiableEventResolverTest { isNoisy = false, timestamp = A_TIMESTAMP, content = content, - contentUrl = null, hasMention = hasMention, ) } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationMediaRepo.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationMediaRepo.kt new file mode 100644 index 0000000000..2657d984a0 --- /dev/null +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationMediaRepo.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.push.impl.notifications.fake + +import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.push.impl.notifications.NotificationMediaRepo +import java.io.File + +class FakeNotificationMediaRepo : NotificationMediaRepo { + override suspend fun getMediaFile( + mediaSource: MediaSource, + mimeType: String?, + body: String?, + ): Result { + return Result.failure(IllegalStateException("Fake class")) + } +}