diff --git a/changelog.d/7257.wip b/changelog.d/7257.wip
new file mode 100644
index 0000000000..c6f9aefbd8
--- /dev/null
+++ b/changelog.d/7257.wip
@@ -0,0 +1 @@
+[Device Management] Save "matrix_client_information" events on login/registration
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/DefaultSessionAccountDataService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/DefaultSessionAccountDataService.kt
index df9dcfb903..c73446cf25 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/DefaultSessionAccountDataService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/DefaultSessionAccountDataService.kt
@@ -66,7 +66,7 @@ internal class DefaultSessionAccountDataService @Inject constructor(
 
     override suspend fun updateUserAccountData(type: String, content: Content) {
         val params = UpdateUserAccountDataTask.AnyParams(type = type, any = content)
-        awaitCallback<Unit> { callback ->
+        awaitCallback { callback ->
             updateUserAccountDataTask.configureWith(params) {
                 this.retryCount = 5 // TODO Need to refactor retrying out into a helper method.
                 this.callback = callback
diff --git a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
index 3f0507305a..c74a945e61 100644
--- a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
+++ b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt
@@ -19,10 +19,10 @@ package im.vector.app.core.di
 import android.content.Context
 import arrow.core.Option
 import im.vector.app.ActiveSessionDataSource
-import im.vector.app.core.extensions.configureAndStart
 import im.vector.app.core.extensions.startSyncing
 import im.vector.app.core.pushers.UnifiedPushHelper
 import im.vector.app.core.services.GuardServiceStarter
+import im.vector.app.core.session.ConfigureAndStartSessionUseCase
 import im.vector.app.features.call.webrtc.WebRtcCallManager
 import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
 import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
@@ -50,6 +50,7 @@ class ActiveSessionHolder @Inject constructor(
         private val sessionInitializer: SessionInitializer,
         private val applicationContext: Context,
         private val authenticationService: AuthenticationService,
+        private val configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase,
 ) {
 
     private var activeSessionReference: AtomicReference<Session?> = AtomicReference()
@@ -109,7 +110,9 @@ class ActiveSessionHolder @Inject constructor(
                 }
                 ?: sessionInitializer.tryInitialize(readCurrentSession = { activeSessionReference.get() }) { session ->
                     setActiveSession(session)
-                    session.configureAndStart(applicationContext, startSyncing = startSync)
+                    runBlocking {
+                        configureAndStartSessionUseCase.execute(session, startSyncing = startSync)
+                    }
                 }
     }
 
diff --git a/vector/src/main/java/im/vector/app/core/extensions/Session.kt b/vector/src/main/java/im/vector/app/core/extensions/Session.kt
index cb1d46efce..4f2d387474 100644
--- a/vector/src/main/java/im/vector/app/core/extensions/Session.kt
+++ b/vector/src/main/java/im/vector/app/core/extensions/Session.kt
@@ -24,20 +24,8 @@ import im.vector.app.core.services.VectorSyncAndroidService
 import im.vector.app.features.session.VectorSessionStore
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
-import org.matrix.android.sdk.api.session.sync.FilterService
 import timber.log.Timber
 
-fun Session.configureAndStart(context: Context, startSyncing: Boolean = true) {
-    Timber.i("Configure and start session for $myUserId. startSyncing: $startSyncing")
-    open()
-    filterService().setFilter(FilterService.FilterPreset.ElementFilter)
-    if (startSyncing) {
-        startSyncing(context)
-    }
-    pushersService().refreshPushers()
-    context.singletonEntryPoint().webRtcCallManager().checkForProtocolsSupportIfNeeded()
-}
-
 fun Session.startSyncing(context: Context) {
     val applicationContext = context.applicationContext
     if (!syncService().hasAlreadySynced()) {
diff --git a/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt b/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt
new file mode 100644
index 0000000000..dfcb92af24
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.core.session
+
+import android.content.Context
+import dagger.hilt.android.qualifiers.ApplicationContext
+import im.vector.app.core.extensions.startSyncing
+import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase
+import im.vector.app.features.call.webrtc.WebRtcCallManager
+import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.sync.FilterService
+import timber.log.Timber
+import javax.inject.Inject
+
+class ConfigureAndStartSessionUseCase @Inject constructor(
+        @ApplicationContext private val context: Context,
+        private val webRtcCallManager: WebRtcCallManager,
+        private val updateMatrixClientInfoUseCase: UpdateMatrixClientInfoUseCase,
+) {
+
+    suspend fun execute(session: Session, startSyncing: Boolean = true) {
+        Timber.i("Configure and start session for ${session.myUserId}. startSyncing: $startSyncing")
+        session.open()
+        session.filterService().setFilter(FilterService.FilterPreset.ElementFilter)
+        if (startSyncing) {
+            session.startSyncing(context)
+        }
+        session.pushersService().refreshPushers()
+        webRtcCallManager.checkForProtocolsSupportIfNeeded()
+        updateMatrixClientInfoUseCase.execute(session)
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/session/clientinfo/GetMatrixClientInfoUseCase.kt b/vector/src/main/java/im/vector/app/core/session/clientinfo/GetMatrixClientInfoUseCase.kt
new file mode 100644
index 0000000000..18b731ea09
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/session/clientinfo/GetMatrixClientInfoUseCase.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.core.session.clientinfo
+
+import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.events.model.toModel
+import javax.inject.Inject
+
+/**
+ * This use case retrieves the current account data event containing extended client info
+ * for a given deviceId.
+ */
+class GetMatrixClientInfoUseCase @Inject constructor() {
+
+    fun execute(session: Session, deviceId: String): MatrixClientInfoContent? {
+        val type = MATRIX_CLIENT_INFO_KEY_PREFIX + deviceId
+        val content = session.accountDataService().getUserAccountDataEvent(type)?.content
+        return content.toModel()
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/session/clientinfo/MatrixClientInfoContent.kt b/vector/src/main/java/im/vector/app/core/session/clientinfo/MatrixClientInfoContent.kt
new file mode 100644
index 0000000000..aacee6edef
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/session/clientinfo/MatrixClientInfoContent.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.core.session.clientinfo
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+@JsonClass(generateAdapter = true)
+data class MatrixClientInfoContent(
+        // app name
+        @Json(name = "name")
+        val name: String? = null,
+        // app version
+        @Json(name = "version")
+        val version: String? = null,
+        // app url (optional, applicable only for web)
+        @Json(name = "url")
+        val url: String? = null,
+)
diff --git a/vector/src/main/java/im/vector/app/core/session/clientinfo/NoDeviceIdError.kt b/vector/src/main/java/im/vector/app/core/session/clientinfo/NoDeviceIdError.kt
new file mode 100644
index 0000000000..c2b4445205
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/session/clientinfo/NoDeviceIdError.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.core.session.clientinfo
+
+class NoDeviceIdError : IllegalStateException("device id is empty")
diff --git a/vector/src/main/java/im/vector/app/core/session/clientinfo/SessionExtendedInfoConstants.kt b/vector/src/main/java/im/vector/app/core/session/clientinfo/SessionExtendedInfoConstants.kt
new file mode 100644
index 0000000000..80f69df1f8
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/session/clientinfo/SessionExtendedInfoConstants.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.core.session.clientinfo
+
+/**
+ * Prefix for the key account data event which holds client info.
+ */
+const val MATRIX_CLIENT_INFO_KEY_PREFIX = "io.element.matrix_client_information."
diff --git a/vector/src/main/java/im/vector/app/core/session/clientinfo/SetMatrixClientInfoUseCase.kt b/vector/src/main/java/im/vector/app/core/session/clientinfo/SetMatrixClientInfoUseCase.kt
new file mode 100644
index 0000000000..5ec428eed0
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/session/clientinfo/SetMatrixClientInfoUseCase.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.core.session.clientinfo
+
+import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.events.model.toContent
+import javax.inject.Inject
+
+/**
+ * This use case sets the account data event containing extended client info.
+ */
+class SetMatrixClientInfoUseCase @Inject constructor() {
+
+    suspend fun execute(session: Session, clientInfo: MatrixClientInfoContent): Result<Unit> = runCatching {
+        val deviceId = session.sessionParams.deviceId.orEmpty()
+        if (deviceId.isNotEmpty()) {
+            val type = MATRIX_CLIENT_INFO_KEY_PREFIX + deviceId
+            session.accountDataService()
+                    .updateUserAccountData(type, clientInfo.toContent())
+        } else {
+            throw NoDeviceIdError()
+        }
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/core/session/clientinfo/UpdateMatrixClientInfoUseCase.kt b/vector/src/main/java/im/vector/app/core/session/clientinfo/UpdateMatrixClientInfoUseCase.kt
new file mode 100644
index 0000000000..a46ca4eedb
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/session/clientinfo/UpdateMatrixClientInfoUseCase.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.core.session.clientinfo
+
+import im.vector.app.core.resources.AppNameProvider
+import im.vector.app.core.resources.BuildMeta
+import org.matrix.android.sdk.api.session.Session
+import timber.log.Timber
+import javax.inject.Inject
+
+/**
+ * This use case updates if needed the account data event containing extended client info.
+ */
+class UpdateMatrixClientInfoUseCase @Inject constructor(
+        private val appNameProvider: AppNameProvider,
+        private val buildMeta: BuildMeta,
+        private val getMatrixClientInfoUseCase: GetMatrixClientInfoUseCase,
+        private val setMatrixClientInfoUseCase: SetMatrixClientInfoUseCase,
+) {
+
+    suspend fun execute(session: Session) = runCatching {
+        val clientInfo = MatrixClientInfoContent(
+                name = appNameProvider.getAppName(),
+                version = buildMeta.versionName
+        )
+        val deviceId = session.sessionParams.deviceId.orEmpty()
+        if (deviceId.isNotEmpty()) {
+            val storedClientInfo = getMatrixClientInfoUseCase.execute(session, deviceId)
+            Timber.d("storedClientInfo=$storedClientInfo, current client info=$clientInfo")
+            if (clientInfo != storedClientInfo) {
+                Timber.d("client info need to be updated")
+                return setMatrixClientInfoUseCase.execute(session, clientInfo)
+            }
+        } else {
+            throw NoDeviceIdError()
+        }
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt
index 79d06a0864..b46f22c58f 100644
--- a/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt
@@ -30,9 +30,9 @@ import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
 import im.vector.app.core.di.MavericksAssistedViewModelFactory
 import im.vector.app.core.di.hiltMavericksViewModelFactory
-import im.vector.app.core.extensions.configureAndStart
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
+import im.vector.app.core.session.ConfigureAndStartSessionUseCase
 import im.vector.app.core.utils.ensureTrailingSlash
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.launch
@@ -64,7 +64,8 @@ class LoginViewModel @AssistedInject constructor(
         private val homeServerConnectionConfigFactory: HomeServerConnectionConfigFactory,
         private val reAuthHelper: ReAuthHelper,
         private val stringProvider: StringProvider,
-        private val homeServerHistoryService: HomeServerHistoryService
+        private val homeServerHistoryService: HomeServerHistoryService,
+        private val configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase,
 ) : VectorViewModel<LoginViewState, LoginAction, LoginViewEvents>(initialState) {
 
     @AssistedFactory
@@ -732,7 +733,7 @@ class LoginViewModel @AssistedInject constructor(
         activeSessionHolder.setActiveSession(session)
 
         authenticationService.reset()
-        session.configureAndStart(applicationContext)
+        configureAndStartSessionUseCase.execute(session)
         setState {
             copy(
                     asyncLoginAction = Success(Unit)
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt
index 4f8a77f25d..9bb52fb1a5 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt
@@ -26,13 +26,13 @@ import im.vector.app.core.di.ActiveSessionHolder
 import im.vector.app.core.di.MavericksAssistedViewModelFactory
 import im.vector.app.core.di.hiltMavericksViewModelFactory
 import im.vector.app.core.extensions.cancelCurrentOnSet
-import im.vector.app.core.extensions.configureAndStart
 import im.vector.app.core.extensions.inferNoConnectivity
 import im.vector.app.core.extensions.isMatrixId
 import im.vector.app.core.extensions.toReducedUrl
 import im.vector.app.core.extensions.vectorStore
 import im.vector.app.core.platform.VectorViewModel
 import im.vector.app.core.resources.StringProvider
+import im.vector.app.core.session.ConfigureAndStartSessionUseCase
 import im.vector.app.core.utils.ensureProtocol
 import im.vector.app.core.utils.ensureTrailingSlash
 import im.vector.app.features.VectorFeatures
@@ -91,6 +91,7 @@ class OnboardingViewModel @AssistedInject constructor(
         private val vectorOverrides: VectorOverrides,
         private val registrationActionHandler: RegistrationActionHandler,
         private val sdkIntProvider: BuildVersionSdkIntProvider,
+        private val configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase,
 ) : VectorViewModel<OnboardingViewState, OnboardingAction, OnboardingViewEvents>(initialState) {
 
     @AssistedFactory
@@ -616,7 +617,7 @@ class OnboardingViewModel @AssistedInject constructor(
         activeSessionHolder.setActiveSession(session)
 
         authenticationService.reset()
-        session.configureAndStart(applicationContext)
+        configureAndStartSessionUseCase.execute(session)
 
         when (authenticationDescription) {
             is AuthenticationDescription.Register -> {
diff --git a/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt
new file mode 100644
index 0000000000..b879806930
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.core.session
+
+import im.vector.app.core.extensions.startSyncing
+import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase
+import im.vector.app.test.fakes.FakeContext
+import im.vector.app.test.fakes.FakeSession
+import im.vector.app.test.fakes.FakeWebRtcCallManager
+import io.mockk.coJustRun
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.just
+import io.mockk.mockk
+import io.mockk.mockkStatic
+import io.mockk.runs
+import io.mockk.unmockkAll
+import io.mockk.verify
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.matrix.android.sdk.api.session.sync.FilterService
+
+class ConfigureAndStartSessionUseCaseTest {
+
+    private val fakeContext = FakeContext()
+    private val fakeWebRtcCallManager = FakeWebRtcCallManager()
+    private val fakeUpdateMatrixClientInfoUseCase = mockk<UpdateMatrixClientInfoUseCase>()
+
+    private val configureAndStartSessionUseCase = ConfigureAndStartSessionUseCase(
+            context = fakeContext.instance,
+            webRtcCallManager = fakeWebRtcCallManager.instance,
+            updateMatrixClientInfoUseCase = fakeUpdateMatrixClientInfoUseCase,
+    )
+
+    @Before
+    fun setup() {
+        mockkStatic("im.vector.app.core.extensions.SessionKt")
+    }
+
+    @After
+    fun tearDown() {
+        unmockkAll()
+    }
+
+    @Test
+    fun `given a session and start sync needed when configuring and starting the session then it should be configured properly`() = runTest {
+        // Given
+        val fakeSession = givenASession()
+        fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds()
+        coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) }
+
+        // When
+        configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true)
+
+        // Then
+        verify { fakeSession.startSyncing(fakeContext.instance) }
+        fakeSession.fakeFilterService.verifySetFilter(FilterService.FilterPreset.ElementFilter)
+        fakeSession.fakePushersService.verifyRefreshPushers()
+        fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded()
+        coVerify { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) }
+    }
+
+    @Test
+    fun `given a session and no start sync needed when configuring and starting the session then it should be configured properly`() = runTest {
+        // Given
+        val fakeSession = givenASession()
+        fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds()
+        coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) }
+
+        // When
+        configureAndStartSessionUseCase.execute(fakeSession, startSyncing = false)
+
+        // Then
+        verify(inverse = true) { fakeSession.startSyncing(fakeContext.instance) }
+        fakeSession.fakeFilterService.verifySetFilter(FilterService.FilterPreset.ElementFilter)
+        fakeSession.fakePushersService.verifyRefreshPushers()
+        fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded()
+        coVerify { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) }
+    }
+
+    private fun givenASession(): FakeSession {
+        val fakeSession = FakeSession()
+        every { fakeSession.open() } just runs
+        fakeSession.fakeFilterService.givenSetFilterSucceeds()
+        every { fakeSession.startSyncing(any()) } just runs
+        fakeSession.fakePushersService.givenRefreshPushersSucceeds()
+        return fakeSession
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/core/session/clientinfo/GetMatrixClientInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/core/session/clientinfo/GetMatrixClientInfoUseCaseTest.kt
new file mode 100644
index 0000000000..4be8218ab5
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/core/session/clientinfo/GetMatrixClientInfoUseCaseTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.core.session.clientinfo
+
+import im.vector.app.test.fakes.FakeSession
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.Test
+
+private const val A_DEVICE_ID = "device-id"
+private const val A_CLIENT_NAME = "client-name"
+private const val A_CLIENT_VERSION = "client-version"
+private const val A_CLIENT_URL = "client-url"
+
+class GetMatrixClientInfoUseCaseTest {
+
+    private val fakeSession = FakeSession()
+
+    private val getMatrixClientInfoUseCase = GetMatrixClientInfoUseCase()
+
+    @Test
+    fun `given a device id and existing content when getting the info then result should contain that info`() {
+        // Given
+        givenClientInfoContent(A_DEVICE_ID)
+        val expectedClientInfo = MatrixClientInfoContent(
+                name = A_CLIENT_NAME,
+                version = A_CLIENT_VERSION,
+                url = A_CLIENT_URL,
+        )
+
+        // When
+        val result = getMatrixClientInfoUseCase.execute(fakeSession, A_DEVICE_ID)
+
+        // Then
+        result shouldBeEqualTo expectedClientInfo
+    }
+
+    private fun givenClientInfoContent(deviceId: String) {
+        val type = MATRIX_CLIENT_INFO_KEY_PREFIX + deviceId
+        val content = mapOf(
+                Pair("name", A_CLIENT_NAME),
+                Pair("version", A_CLIENT_VERSION),
+                Pair("url", A_CLIENT_URL),
+        )
+        fakeSession
+                .fakeSessionAccountDataService
+                .givenGetUserAccountDataEventReturns(type, content)
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/core/session/clientinfo/SetMatrixClientInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/core/session/clientinfo/SetMatrixClientInfoUseCaseTest.kt
new file mode 100644
index 0000000000..4345de45c4
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/core/session/clientinfo/SetMatrixClientInfoUseCaseTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.core.session.clientinfo
+
+import im.vector.app.test.fakes.FakeSession
+import kotlinx.coroutines.test.runTest
+import org.amshove.kluent.shouldBe
+import org.amshove.kluent.shouldBeEqualTo
+import org.amshove.kluent.shouldBeInstanceOf
+import org.junit.Test
+import org.matrix.android.sdk.api.session.events.model.toContent
+
+private const val A_DEVICE_ID = "device-id"
+
+class SetMatrixClientInfoUseCaseTest {
+
+    private val fakeSession = FakeSession()
+
+    private val setMatrixClientInfoUseCase = SetMatrixClientInfoUseCase()
+
+    @Test
+    fun `given client info and no error when setting the info then account data is correctly updated`() = runTest {
+        // Given
+        val type = MATRIX_CLIENT_INFO_KEY_PREFIX + A_DEVICE_ID
+        val clientInfo = givenClientInfo()
+        val content = clientInfo.toContent()
+        fakeSession
+                .givenSessionId(A_DEVICE_ID)
+        fakeSession
+                .fakeSessionAccountDataService
+                .givenUpdateUserAccountDataEventSucceeds()
+
+        // When
+        val result = setMatrixClientInfoUseCase.execute(fakeSession, clientInfo)
+
+        // Then
+        result.isSuccess shouldBe true
+        fakeSession
+                .fakeSessionAccountDataService
+                .verifyUpdateUserAccountDataEventSucceeds(type, content)
+    }
+
+    @Test
+    fun `given client info and error during update when setting the info then result is failure`() = runTest {
+        // Given
+        val type = MATRIX_CLIENT_INFO_KEY_PREFIX + A_DEVICE_ID
+        val clientInfo = givenClientInfo()
+        val content = clientInfo.toContent()
+        fakeSession
+                .givenSessionId(A_DEVICE_ID)
+        val error = Exception()
+        fakeSession
+                .fakeSessionAccountDataService
+                .givenUpdateUserAccountDataEventFailsWithError(error)
+
+        // When
+        val result = setMatrixClientInfoUseCase.execute(fakeSession, clientInfo)
+
+        // Then
+        result.isFailure shouldBe true
+        result.exceptionOrNull() shouldBeEqualTo error
+        fakeSession
+                .fakeSessionAccountDataService
+                .verifyUpdateUserAccountDataEventSucceeds(type, content)
+    }
+
+    @Test
+    fun `given client info and null device id when setting the info then result is failure`() = runTest {
+        // Given
+        val type = MATRIX_CLIENT_INFO_KEY_PREFIX + A_DEVICE_ID
+        val clientInfo = givenClientInfo()
+        val content = clientInfo.toContent()
+        fakeSession
+                .givenSessionId(null)
+
+        // When
+        val result = setMatrixClientInfoUseCase.execute(fakeSession, clientInfo)
+
+        // Then
+        result.isFailure shouldBe true
+        result.exceptionOrNull() shouldBeInstanceOf NoDeviceIdError::class
+        fakeSession
+                .fakeSessionAccountDataService
+                .verifyUpdateUserAccountDataEventSucceeds(type, content, inverse = true)
+    }
+
+    private fun givenClientInfo() = MatrixClientInfoContent(
+            name = "name",
+            version = "version",
+            url = null,
+    )
+}
diff --git a/vector/src/test/java/im/vector/app/core/session/clientinfo/UpdateMatrixClientInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/core/session/clientinfo/UpdateMatrixClientInfoUseCaseTest.kt
new file mode 100644
index 0000000000..7f1727ff37
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/core/session/clientinfo/UpdateMatrixClientInfoUseCaseTest.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.core.session.clientinfo
+
+import im.vector.app.core.resources.BuildMeta
+import im.vector.app.test.fakes.FakeAppNameProvider
+import im.vector.app.test.fakes.FakeSession
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.mockk
+import kotlinx.coroutines.test.runTest
+import org.amshove.kluent.shouldBe
+import org.amshove.kluent.shouldBeEqualTo
+import org.amshove.kluent.shouldBeInstanceOf
+import org.junit.Test
+
+private const val AN_APP_NAME_1 = "app_name_1"
+private const val AN_APP_NAME_2 = "app_name_2"
+private const val A_VERSION_NAME_1 = "version_name_1"
+private const val A_VERSION_NAME_2 = "version_name_2"
+private const val A_SESSION_ID = "session-id"
+
+class UpdateMatrixClientInfoUseCaseTest {
+
+    private val fakeSession = FakeSession()
+    private val fakeAppNameProvider = FakeAppNameProvider()
+    private val fakeBuildMeta = mockk<BuildMeta>()
+    private val getMatrixClientInfoUseCase = mockk<GetMatrixClientInfoUseCase>()
+    private val setMatrixClientInfoUseCase = mockk<SetMatrixClientInfoUseCase>()
+
+    private val updateMatrixClientInfoUseCase = UpdateMatrixClientInfoUseCase(
+            appNameProvider = fakeAppNameProvider,
+            buildMeta = fakeBuildMeta,
+            getMatrixClientInfoUseCase = getMatrixClientInfoUseCase,
+            setMatrixClientInfoUseCase = setMatrixClientInfoUseCase,
+    )
+
+    @Test
+    fun `given current client info is different than the stored one when trying to update then new client info is set`() = runTest {
+        // Given
+        givenCurrentAppName(AN_APP_NAME_1)
+        givenCurrentVersionName(A_VERSION_NAME_1)
+        givenStoredClientInfo(AN_APP_NAME_2, A_VERSION_NAME_2)
+        givenSetClientInfoSucceeds()
+        val expectedClientInfoToSet = MatrixClientInfoContent(
+                name = AN_APP_NAME_1,
+                version = A_VERSION_NAME_1,
+        )
+
+        // When
+        val result = updateMatrixClientInfoUseCase.execute(fakeSession)
+
+        // Then
+        result.isSuccess shouldBe true
+        coVerify { setMatrixClientInfoUseCase.execute(fakeSession, match { it == expectedClientInfoToSet }) }
+    }
+
+    @Test
+    fun `given error during set of new client info when trying to update then result is failure`() = runTest {
+        // Given
+        givenCurrentAppName(AN_APP_NAME_1)
+        givenCurrentVersionName(A_VERSION_NAME_1)
+        givenStoredClientInfo(AN_APP_NAME_2, A_VERSION_NAME_2)
+        val error = Exception()
+        givenSetClientInfoFails(error)
+        val expectedClientInfoToSet = MatrixClientInfoContent(
+                name = AN_APP_NAME_1,
+                version = A_VERSION_NAME_1,
+        )
+
+        // When
+        val result = updateMatrixClientInfoUseCase.execute(fakeSession)
+
+        // Then
+        result.isFailure shouldBe true
+        result.exceptionOrNull() shouldBeEqualTo error
+        coVerify { setMatrixClientInfoUseCase.execute(fakeSession, match { it == expectedClientInfoToSet }) }
+    }
+
+    @Test
+    fun `given current client info is equal to the stored one when trying to update then nothing is done`() = runTest {
+        // Given
+        givenCurrentAppName(AN_APP_NAME_1)
+        givenCurrentVersionName(A_VERSION_NAME_1)
+        givenStoredClientInfo(AN_APP_NAME_1, A_VERSION_NAME_1)
+
+        // When
+        val result = updateMatrixClientInfoUseCase.execute(fakeSession)
+
+        // Then
+        result.isSuccess shouldBe true
+        coVerify(inverse = true) { setMatrixClientInfoUseCase.execute(fakeSession, any()) }
+    }
+
+    @Test
+    fun `given no session id for current session when trying to update then nothing is done`() = runTest {
+        // Given
+        givenCurrentAppName(AN_APP_NAME_1)
+        givenCurrentVersionName(A_VERSION_NAME_1)
+        fakeSession.givenSessionId(null)
+
+        // When
+        val result = updateMatrixClientInfoUseCase.execute(fakeSession)
+
+        // Then
+        result.isFailure shouldBe true
+        result.exceptionOrNull() shouldBeInstanceOf NoDeviceIdError::class
+        coVerify(inverse = true) { setMatrixClientInfoUseCase.execute(fakeSession, any()) }
+    }
+
+    private fun givenCurrentAppName(appName: String) {
+        fakeAppNameProvider.givenAppName(appName)
+    }
+
+    private fun givenCurrentVersionName(versionName: String) {
+        every { fakeBuildMeta.versionName } returns versionName
+    }
+
+    private fun givenStoredClientInfo(appName: String, versionName: String) {
+        fakeSession.givenSessionId(A_SESSION_ID)
+        every { getMatrixClientInfoUseCase.execute(fakeSession, A_SESSION_ID) } returns MatrixClientInfoContent(
+                name = appName,
+                version = versionName,
+        )
+    }
+
+    private fun givenSetClientInfoSucceeds() {
+        coEvery { setMatrixClientInfoUseCase.execute(any(), any()) } returns Result.success(Unit)
+    }
+
+    private fun givenSetClientInfoFails(error: Throwable) {
+        coEvery { setMatrixClientInfoUseCase.execute(any(), any()) } returns Result.failure(error)
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt b/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt
index c3f6b86cb4..82adc70fe3 100644
--- a/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt
+++ b/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt
@@ -20,6 +20,7 @@ import android.net.Uri
 import android.os.Build
 import com.airbnb.mvrx.test.MavericksTestRule
 import im.vector.app.R
+import im.vector.app.core.session.ConfigureAndStartSessionUseCase
 import im.vector.app.features.login.LoginConfig
 import im.vector.app.features.login.LoginMode
 import im.vector.app.features.login.ReAuthHelper
@@ -50,6 +51,7 @@ import im.vector.app.test.fixtures.a401ServerError
 import im.vector.app.test.fixtures.aHomeServerCapabilities
 import im.vector.app.test.fixtures.anUnrecognisedCertificateError
 import im.vector.app.test.test
+import io.mockk.mockk
 import kotlinx.coroutines.test.runTest
 import org.amshove.kluent.shouldBeEqualTo
 import org.junit.Before
@@ -111,6 +113,7 @@ class OnboardingViewModelTest {
     private val fakeStartAuthenticationFlowUseCase = FakeStartAuthenticationFlowUseCase()
     private val fakeHomeServerHistoryService = FakeHomeServerHistoryService()
     private val fakeLoginWizard = FakeLoginWizard()
+    private val fakeConfigureAndStartSessionUseCase = mockk<ConfigureAndStartSessionUseCase>()
 
     private var initialState = OnboardingViewState()
     private lateinit var viewModel: OnboardingViewModel
@@ -1093,6 +1096,7 @@ class OnboardingViewModelTest {
                 FakeVectorOverrides(),
                 fakeRegistrationActionHandler.instance,
                 TestBuildVersionSdkIntProvider().also { it.value = Build.VERSION_CODES.O },
+                fakeConfigureAndStartSessionUseCase,
         ).also {
             viewModel = it
             initialState = state
@@ -1132,7 +1136,7 @@ class OnboardingViewModelTest {
     private fun givenInitialisesSession(session: Session) {
         fakeActiveSessionHolder.expectSetsActiveSession(session)
         fakeAuthenticationService.expectReset()
-        fakeSession.expectStartsSyncing()
+        fakeSession.expectStartsSyncing(fakeConfigureAndStartSessionUseCase)
     }
 
     private fun givenRegistrationResultFor(action: RegisterAction, result: RegistrationActionHandler.Result) {
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeFilterService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeFilterService.kt
new file mode 100644
index 0000000000..4332368127
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeFilterService.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.test.fakes
+
+import io.mockk.every
+import io.mockk.just
+import io.mockk.mockk
+import io.mockk.runs
+import io.mockk.verify
+import org.matrix.android.sdk.api.session.sync.FilterService
+
+class FakeFilterService : FilterService by mockk() {
+
+    fun givenSetFilterSucceeds() {
+        every { setFilter(any()) } just runs
+    }
+
+    fun verifySetFilter(filterPreset: FilterService.FilterPreset) {
+        verify { setFilter(filterPreset) }
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakePushersService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakePushersService.kt
index d506f53e60..4ad3052538 100644
--- a/vector/src/test/java/im/vector/app/test/fakes/FakePushersService.kt
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakePushersService.kt
@@ -20,6 +20,7 @@ import androidx.lifecycle.liveData
 import io.mockk.Ordering
 import io.mockk.coVerify
 import io.mockk.every
+import io.mockk.justRun
 import io.mockk.mockk
 import io.mockk.slot
 import io.mockk.verify
@@ -56,4 +57,12 @@ class FakePushersService : PushersService by mockk(relaxed = true) {
         verify { enqueueAddHttpPusher(capture(httpPusherSlot)) }
         return httpPusherSlot.captured
     }
+
+    fun givenRefreshPushersSucceeds() {
+        justRun { refreshPushers() }
+    }
+
+    fun verifyRefreshPushers() {
+        verify { refreshPushers() }
+    }
 }
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt
index bf437c123b..c40e4a8fc4 100644
--- a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt
@@ -16,9 +16,9 @@
 
 package im.vector.app.test.fakes
 
-import im.vector.app.core.extensions.configureAndStart
 import im.vector.app.core.extensions.startSyncing
 import im.vector.app.core.extensions.vectorStore
+import im.vector.app.core.session.ConfigureAndStartSessionUseCase
 import im.vector.app.features.session.VectorSessionStore
 import im.vector.app.test.testCoroutineDispatchers
 import io.mockk.coEvery
@@ -43,6 +43,8 @@ class FakeSession(
         val fakeRoomService: FakeRoomService = FakeRoomService(),
         val fakePushersService: FakePushersService = FakePushersService(),
         private val fakeEventService: FakeEventService = FakeEventService(),
+        val fakeSessionAccountDataService: FakeSessionAccountDataService = FakeSessionAccountDataService(),
+        val fakeFilterService: FakeFilterService = FakeFilterService(),
 ) : Session by mockk(relaxed = true) {
 
     init {
@@ -60,6 +62,8 @@ class FakeSession(
     override fun roomService() = fakeRoomService
     override fun eventService() = fakeEventService
     override fun pushersService() = fakePushersService
+    override fun accountDataService() = fakeSessionAccountDataService
+    override fun filterService() = fakeFilterService
 
     fun givenVectorStore(vectorSessionStore: VectorSessionStore) {
         coEvery {
@@ -69,9 +73,9 @@ class FakeSession(
         }
     }
 
-    fun expectStartsSyncing() {
+    fun expectStartsSyncing(configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase) {
         coJustRun {
-            this@FakeSession.configureAndStart(any(), startSyncing = true)
+            configureAndStartSessionUseCase.execute(this@FakeSession, startSyncing = true)
             this@FakeSession.startSyncing(any())
         }
     }
@@ -80,7 +84,7 @@ class FakeSession(
         every { this@FakeSession.sessionParams } returns sessionParams
     }
 
-    fun givenSessionId(sessionId: String): SessionParams {
+    fun givenSessionId(sessionId: String?): SessionParams {
         val sessionParams = mockk<SessionParams>()
         every { sessionParams.deviceId } returns sessionId
         givenSessionParams(sessionParams)
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSessionAccountDataService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSessionAccountDataService.kt
new file mode 100644
index 0000000000..34a0d8edb3
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSessionAccountDataService.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.test.fakes
+
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.just
+import io.mockk.mockk
+import io.mockk.runs
+import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
+import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
+import org.matrix.android.sdk.api.session.events.model.Content
+
+class FakeSessionAccountDataService : SessionAccountDataService by mockk() {
+
+    fun givenGetUserAccountDataEventReturns(type: String, content: Content) {
+        every { getUserAccountDataEvent(type) } returns UserAccountDataEvent(type, content)
+    }
+
+    fun givenUpdateUserAccountDataEventSucceeds() {
+        coEvery { updateUserAccountData(any(), any()) } just runs
+    }
+
+    fun givenUpdateUserAccountDataEventFailsWithError(error: Exception) {
+        coEvery { updateUserAccountData(any(), any()) } throws error
+    }
+
+    fun verifyUpdateUserAccountDataEventSucceeds(type: String, content: Content, inverse: Boolean = false) {
+        coVerify(inverse = inverse) { updateUserAccountData(type, content) }
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeWebRtcCallManager.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeWebRtcCallManager.kt
new file mode 100644
index 0000000000..b3664bafa1
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeWebRtcCallManager.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022 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 im.vector.app.test.fakes
+
+import im.vector.app.features.call.webrtc.WebRtcCallManager
+import io.mockk.every
+import io.mockk.just
+import io.mockk.mockk
+import io.mockk.runs
+import io.mockk.verify
+
+class FakeWebRtcCallManager {
+
+    val instance = mockk<WebRtcCallManager>()
+
+    fun givenCheckForProtocolsSupportIfNeededSucceeds() {
+        every { instance.checkForProtocolsSupportIfNeeded() } just runs
+    }
+
+    fun verifyCheckForProtocolsSupportIfNeeded() {
+        verify { instance.checkForProtocolsSupportIfNeeded() }
+    }
+}