diff --git a/app/src/main/kotlin/io/element/android/x/di/AppModule.kt b/app/src/main/kotlin/io/element/android/x/di/AppModule.kt index d98a05321d..02f132d34a 100644 --- a/app/src/main/kotlin/io/element/android/x/di/AppModule.kt +++ b/app/src/main/kotlin/io/element/android/x/di/AppModule.kt @@ -35,6 +35,7 @@ import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.MainScope import kotlinx.coroutines.plus +import kotlinx.serialization.json.Json import java.io.File @BindingContainer @@ -120,4 +121,10 @@ object AppModule { fun providesEmojibaseProvider(@ApplicationContext context: Context): EmojibaseProvider { return DefaultEmojibaseProvider(context) } + + @Provides + @SingleIn(AppScope::class) + fun providesJson(): Json = Json { + ignoreUnknownKeys = true + } } diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt index 06929093f5..7604dbae18 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt @@ -64,6 +64,7 @@ class CallScreenPresenter( private val appForegroundStateService: AppForegroundStateService, @AppCoroutineScope private val appCoroutineScope: CoroutineScope, + private val widgetMessageSerializer: WidgetMessageSerializer, ) : Presenter { @AssistedFactory interface Factory { @@ -258,7 +259,7 @@ class CallScreenPresenter( } private fun parseMessage(message: String): WidgetMessage? { - return WidgetMessageSerializer.deserialize(message).getOrNull() + return widgetMessageSerializer.deserialize(message).getOrNull() } private fun sendHangupMessage(widgetId: String, messageInterceptor: WidgetMessageInterceptor) { @@ -269,7 +270,7 @@ class CallScreenPresenter( action = WidgetMessage.Action.HangUp, data = null, ) - messageInterceptor.sendMessage(WidgetMessageSerializer.serialize(message)) + messageInterceptor.sendMessage(widgetMessageSerializer.serialize(message)) } private fun CoroutineScope.close(widgetDriver: MatrixWidgetDriver?, navigator: CallScreenNavigator) = launch(dispatchers.io) { diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WidgetMessageSerializer.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WidgetMessageSerializer.kt index a21cadab7a..2beaea7061 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WidgetMessageSerializer.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WidgetMessageSerializer.kt @@ -7,18 +7,20 @@ package io.element.android.features.call.impl.utils +import dev.zacsweers.metro.Inject import io.element.android.features.call.impl.data.WidgetMessage import io.element.android.libraries.core.extensions.runCatchingExceptions import kotlinx.serialization.json.Json -object WidgetMessageSerializer { - private val coder = Json { ignoreUnknownKeys = true } - +@Inject +class WidgetMessageSerializer( + private val json: Json, +) { fun deserialize(message: String): Result { - return runCatchingExceptions { coder.decodeFromString(WidgetMessage.serializer(), message) } + return runCatchingExceptions { json.decodeFromString(WidgetMessage.serializer(), message) } } fun serialize(message: WidgetMessage): String { - return coder.encodeToString(WidgetMessage.serializer(), message) + return json.encodeToString(WidgetMessage.serializer(), message) } } diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt index 47a91afa1c..c3a68994da 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt @@ -16,6 +16,7 @@ import io.element.android.features.call.api.CallType import io.element.android.features.call.impl.ui.CallScreenEvents import io.element.android.features.call.impl.ui.CallScreenNavigator import io.element.android.features.call.impl.ui.CallScreenPresenter +import io.element.android.features.call.impl.utils.WidgetMessageSerializer import io.element.android.features.call.utils.FakeActiveCallManager import io.element.android.features.call.utils.FakeCallWidgetProvider import io.element.android.features.call.utils.FakeWidgetMessageInterceptor @@ -46,11 +47,13 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest +import kotlinx.serialization.json.Json import org.junit.Rule import org.junit.Test import kotlin.time.Duration.Companion.seconds -@OptIn(ExperimentalCoroutinesApi::class) class CallScreenPresenterTest { +@OptIn(ExperimentalCoroutinesApi::class) +class CallScreenPresenterTest { @get:Rule val warmUpRule = WarmUpRule() @@ -409,6 +412,7 @@ import kotlin.time.Duration.Companion.seconds languageTagProvider = FakeLanguageTagProvider("en-US"), appForegroundStateService = appForegroundStateService, appCoroutineScope = backgroundScope, + widgetMessageSerializer = WidgetMessageSerializer(Json { ignoreUnknownKeys = true }), ) } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/MessageParser.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/MessageParser.kt index 8450aef1d3..8762bc5e46 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/MessageParser.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/MessageParser.kt @@ -26,10 +26,10 @@ interface MessageParser { @Inject class DefaultMessageParser( private val accountProviderDataSource: AccountProviderDataSource, + private val json: Json, ) : MessageParser { override fun parse(message: String): ExternalSession { - val parser = Json { ignoreUnknownKeys = true } - val response = parser.decodeFromString(MobileRegistrationResponse.serializer(), message) + val response = json.decodeFromString(MobileRegistrationResponse.serializer(), message) val userId = response.userId ?: error("No user ID in response") val homeServer = response.homeServer ?: accountProviderDataSource.flow.value.url val accessToken = response.accessToken ?: error("No access token in response") diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/createaccount/DefaultMessageParserTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/createaccount/DefaultMessageParserTest.kt index a1fbbc0fe2..fa97a2b1fc 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/createaccount/DefaultMessageParserTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/createaccount/DefaultMessageParserTest.kt @@ -13,6 +13,7 @@ import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource import io.element.android.libraries.matrix.api.auth.external.ExternalSession import kotlinx.serialization.SerializationException +import kotlinx.serialization.json.Json import org.junit.Assert.assertThrows import org.junit.Test @@ -68,7 +69,8 @@ class DefaultMessageParserTest { private fun createDefaultMessageParser(): DefaultMessageParser { return DefaultMessageParser( - AccountProviderDataSource(FakeEnterpriseService()) + accountProviderDataSource = AccountProviderDataSource(FakeEnterpriseService()), + json = Json { ignoreUnknownKeys = true }, ) } } diff --git a/libraries/network/src/main/kotlin/io/element/android/libraries/network/NetworkModule.kt b/libraries/network/src/main/kotlin/io/element/android/libraries/network/NetworkModule.kt index 6ede5a0c48..b749ebec39 100644 --- a/libraries/network/src/main/kotlin/io/element/android/libraries/network/NetworkModule.kt +++ b/libraries/network/src/main/kotlin/io/element/android/libraries/network/NetworkModule.kt @@ -15,7 +15,6 @@ import dev.zacsweers.metro.SingleIn import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.network.interceptors.FormattedJsonHttpLogger import io.element.android.libraries.network.interceptors.UserAgentInterceptor -import kotlinx.serialization.json.Json import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import java.util.concurrent.TimeUnit @@ -35,12 +34,6 @@ object NetworkModule { addInterceptor(userAgentInterceptor) if (buildMeta.isDebuggable) addInterceptor(providesHttpLoggingInterceptor()) }.build() - - @Provides - @SingleIn(AppScope::class) - fun providesJson(): Json = Json { - ignoreUnknownKeys = true - } } private fun providesHttpLoggingInterceptor(): HttpLoggingInterceptor { diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushParser.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushParser.kt index f1290636c3..14a0bf3e85 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushParser.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushParser.kt @@ -13,9 +13,9 @@ import io.element.android.libraries.pushproviders.api.PushData import kotlinx.serialization.json.Json @Inject -class UnifiedPushParser { - private val json by lazy { Json { ignoreUnknownKeys = true } } - +class UnifiedPushParser( + private val json: Json, +) { fun parse(message: ByteArray, clientSecret: String): PushData? { return tryOrNull { json.decodeFromString(String(message)) }?.toPushData(clientSecret) } diff --git a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt index 81bbab5ab8..c34a0a12d3 100644 --- a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt +++ b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt @@ -22,7 +22,7 @@ import timber.log.Timber @Inject class DefaultSessionWellknownRetriever( private val matrixClient: MatrixClient, - private val parser: Json, + private val json: Json, ) : SessionWellknownRetriever { private val domain by lazy { matrixClient.userIdServerName() } @@ -32,7 +32,7 @@ class DefaultSessionWellknownRetriever( .getUrl(url) .mapCatchingExceptions { val data = String(it) - parser.decodeFromString(InternalWellKnown.serializer(), data) + json.decodeFromString(InternalWellKnown.serializer(), data) } .onFailure { Timber.e(it, "Failed to retrieve .well-known from $domain") } .map { it.map() } @@ -45,7 +45,7 @@ class DefaultSessionWellknownRetriever( .getUrl(url) .mapCatchingExceptions { val data = String(it) - parser.decodeFromString(InternalElementWellKnown.serializer(), data) + json.decodeFromString(InternalElementWellKnown.serializer(), data) } .onFailure { Timber.e(it, "Failed to retrieve Element .well-known from $domain") } .map { it.map() } diff --git a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt index 624370466a..2c788cae63 100644 --- a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt +++ b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt @@ -244,6 +244,6 @@ class DefaultSessionWellknownRetrieverTest { userIdServerNameLambda = { "user.domain.org" }, getUrlLambda = getUrlLambda, ), - parser = Json { ignoreUnknownKeys = true } + json = Json { ignoreUnknownKeys = true }, ) }