diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index db1a9beb84433853e479227c98b27bbb8e5e0fa1..e0012e9c65b406634d5f02f89100584b1fe860fa 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -13,7 +13,10 @@ jobs:
         uses: actions/checkout@v2
 
       - name: Build docs
-        run: ./gradlew dokkaHtml
+        run: |
+          sed -i.bak "s/.*nightly documentation.*//" ./matrix-sdk-android/docs/modules.md
+          rm ./matrix-sdk-android/docs/modules.md.bak
+          ./gradlew dokkaHtml
 
       - name: Deploy docs
         uses: peaceiris/actions-gh-pages@v3
diff --git a/CHANGES.md b/CHANGES.md
index 292e34de5a789dd3ddeba696170a0b719610af50..5e0467aa9398530c5f658beb434cb0833b65da67 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,20 @@
 Please also refer to the Changelog of Element Android: https://github.com/vector-im/element-android/blob/main/CHANGES.md
 
+Changes in Matrix-SDK 1.4.16 (2022-05-23)
+===================================================
+
+Imported from Element 1.4.16. (https://github.com/vector-im/element-android/releases/tag/v1.4.16)
+
+SDK API changes ⚠️
+------------------
+- New API to enable/disable key forwarding CryptoService#enableKeyGossiping()
+- New API to limit room key request only to own devices MXCryptoConfig#limitRoomKeyRequestsToMyDevices
+- Event Trail API has changed, now using AuditTrail events
+- New API to manually accept an incoming key request CryptoService#manuallyAcceptRoomKeyRequest() ([#5559](https://github.com/vector-im/element-android/issues/5559))
+- Small change in the Matrix class: deprecated methods have been removed and the constructor is now public. Also the fun `workerFactory()` has been renamed to `getWorkerFactory()` ([#5887](https://github.com/vector-im/element-android/issues/5887))
+- Including SSL/TLS error handing when doing WellKnown lookups without a custom HomeServerConnectionConfig ([#5965](https://github.com/vector-im/element-android/issues/5965))
+
+
 Changes in Matrix-SDK 1.4.14 (2022-05-10)
 ===================================================
 
diff --git a/build.gradle b/build.gradle
index 56e7e1de82cc529b9541ec215cf6955554b987b8..757d08ddcc2264b4e4a3fd53ea90aa793c4e621d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -15,7 +15,7 @@ buildscript {
         classpath libs.gradle.gradlePlugin
         classpath libs.gradle.kotlinPlugin
         classpath 'com.vanniktech:gradle-maven-publish-plugin:0.18.0'
-        classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.6.20"
+        classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.6.21"
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
     }
diff --git a/dependencies.gradle b/dependencies.gradle
index 7666a3bf9f8b4cc9929a65f2b0822eaae753cb33..10f9539e5ac16392be44fd7774c8c397411f9216 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -7,26 +7,26 @@ ext.versions = [
         'targetCompat'      : JavaVersion.VERSION_11,
 ]
 
-def gradle = "7.0.4"
+def gradle = "7.2.0"
 // Ref: https://kotlinlang.org/releases.html
-def kotlin = "1.6.0"
-def kotlinCoroutines = "1.6.0"
-def dagger = "2.40.5"
+def kotlin = "1.6.21"
+def kotlinCoroutines = "1.6.1"
+def dagger = "2.42"
 def retrofit = "2.9.0"
 def arrow = "0.8.2"
 def markwon = "4.6.2"
 def moshi = "1.13.0"
-def lifecycle = "2.4.0"
+def lifecycle = "2.4.1"
 def flowBinding = "1.2.0"
 def epoxy = "4.6.2"
-def mavericks = "2.5.0"
-def glide = "4.12.0"
+def mavericks = "2.6.1"
+def glide = "4.13.2"
 def bigImageViewer = "1.8.1"
-def jjwt = "0.11.2"
-def vanniktechEmoji = "0.8.0"
+def jjwt = "0.11.5"
+def vanniktechEmoji = "0.9.0"
 
 // Testing
-def mockk = "1.12.1"
+def mockk = "1.12.4"
 def espresso = "3.4.0"
 def androidxTest = "1.4.0"
 def androidxOrchestrator = "1.4.1"
@@ -45,15 +45,15 @@ ext.libs = [
                 'coroutinesTest'          : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines"
         ],
         androidx    : [
-                'appCompat'               : "androidx.appcompat:appcompat:1.4.0",
+                'appCompat'               : "androidx.appcompat:appcompat:1.4.1",
                 'core'                    : "androidx.core:core-ktx:1.7.0",
                 'recyclerview'            : "androidx.recyclerview:recyclerview:1.2.1",
                 'exifinterface'           : "androidx.exifinterface:exifinterface:1.3.3",
-                'fragmentKtx'             : "androidx.fragment:fragment-ktx:1.4.0",
-                'constraintLayout'        : "androidx.constraintlayout:constraintlayout:2.1.2",
+                'fragmentKtx'             : "androidx.fragment:fragment-ktx:1.4.1",
+                'constraintLayout'        : "androidx.constraintlayout:constraintlayout:2.1.3",
                 'work'                    : "androidx.work:work-runtime-ktx:2.7.1",
                 'autoFill'                : "androidx.autofill:autofill:1.1.0",
-                'preferenceKtx'           : "androidx.preference:preference-ktx:1.1.1",
+                'preferenceKtx'           : "androidx.preference:preference-ktx:1.2.0",
                 'junit'                   : "androidx.test.ext:junit:1.1.3",
                 'lifecycleCommon'         : "androidx.lifecycle:lifecycle-common:$lifecycle",
                 'lifecycleLivedata'       : "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle",
@@ -72,7 +72,7 @@ ext.libs = [
                 'espressoIntents'         : "androidx.test.espresso:espresso-intents:$espresso"
         ],
         google      : [
-                'material'                : "com.google.android.material:material:1.5.0"
+                'material'                : "com.google.android.material:material:1.6.0"
         ],
         dagger      : [
                 'dagger'                  : "com.google.dagger:dagger:$dagger",
diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle
index 8422e05930f845e53890a281bcda60c766766add..76869fccf1c70d38dcafb076c1b239498b3a8fea 100644
--- a/dependencies_groups.gradle
+++ b/dependencies_groups.gradle
@@ -123,6 +123,7 @@ ext.groups = [
                         'io.github.detekt.sarif4k',
                         'io.github.microutils',
                         'io.github.reactivecircus.flowbinding',
+                        'io.gitlab.arturbosch.detekt',
                         'io.grpc',
                         'io.jsonwebtoken',
                         'io.kindedj',
@@ -195,6 +196,7 @@ ext.groups = [
                         'org.testng',
                         'org.threeten',
                         'org.webjars',
+                        'org.yaml',
                         'ru.noties',
                         'xerces',
                         'xml-apis',
diff --git a/gradle.properties b/gradle.properties
index 6402e3ad3a9b07b41f5e6aa166f272d93357f297..97384e645c0a6dbdf353943d4d298f288515ce73 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -26,7 +26,7 @@ vector.httpLogLevel=NONE
 # Ref: https://github.com/vanniktech/gradle-maven-publish-plugin
 GROUP=org.matrix.android
 POM_ARTIFACT_ID=matrix-android-sdk2
-VERSION_NAME=1.4.14
+VERSION_NAME=1.4.16
 
 POM_PACKAGING=aar
 
diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle
index 8362d35960f8a43d103a6599481dfe6d90c2fba3..d04a675cbaa67e173db8b91b14a0622e057d27c3 100644
--- a/matrix-sdk-android/build.gradle
+++ b/matrix-sdk-android/build.gradle
@@ -9,7 +9,10 @@ apply plugin: "com.vanniktech.maven.publish"
 
 buildscript {
     repositories {
-        mavenCentral()
+        // Do not use `mavenCentral()`, it prevents Dependabot from working properly
+        maven {
+            url 'https://repo1.maven.org/maven2'
+        }
     }
     dependencies {
         classpath "io.realm:realm-gradle-plugin:10.9.0"
@@ -20,7 +23,7 @@ dokkaHtml {
     dokkaSourceSets {
         configureEach {
             // Emit warnings about not documented members.
-            reportUndocumented.set(true)
+            // reportUndocumented.set(true)
             // Suppress legacy Riot's packages.
             perPackageOption {
                 matchingRegex.set("org.matrix.android.sdk.internal.legacy.riot")
@@ -101,6 +104,9 @@ android {
         freeCompilerArgs += [
                 // Disabled for now, there are too many errors. Could be handled in another dedicated PR
                 // '-Xexplicit-api=strict', // or warning
+                "-opt-in=kotlin.RequiresOptIn",
+                // Opt in for kotlinx.coroutines.FlowPreview
+                "-opt-in=kotlinx.coroutines.FlowPreview",
         ]
     }
 
@@ -178,7 +184,7 @@ dependencies {
     implementation libs.arrow.instances
 
     // olm lib is now hosted in MavenCentral
-    implementation 'org.matrix.android:olm-sdk:3.2.10'
+    implementation 'org.matrix.android:olm-sdk:3.2.11'
 
     // DI
     implementation libs.dagger.dagger
@@ -195,7 +201,7 @@ dependencies {
     implementation libs.apache.commonsImaging
 
     // Phone number https://github.com/google/libphonenumber
-    implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.47'
+    implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.48'
 
     testImplementation libs.tests.junit
     testImplementation 'org.robolectric:robolectric:4.7.3'
diff --git a/matrix-sdk-android/docs/modules.md b/matrix-sdk-android/docs/modules.md
index edf5af64d024d6a214e3657bc73701ec4182b214..fb082c1bc216f67f578b63d51c747e288293f329 100644
--- a/matrix-sdk-android/docs/modules.md
+++ b/matrix-sdk-android/docs/modules.md
@@ -1,5 +1,8 @@
 # Module matrix-sdk-android
 
+<!-- Note: the line below will appear only when the documentation is generated from Element-Android project, and not when it's generated from the SDK project -->
+**Note**: You are viewing the nightly documentation of the Android Matrix SDK library. The documentation of the released library can be found here: [https://matrix-org.github.io/matrix-android-sdk2/](https://matrix-org.github.io/matrix-android-sdk2/)
+
 ## Welcome to the matrix-sdk-android documentation!
 
 This pages list the complete API that this SDK is exposing to a client application.
@@ -8,11 +11,11 @@ This pages list the complete API that this SDK is exposing to a client applicati
 
 A few entry points:
 
-- **Matrix**: The app will have to create and manage a Matrix object.
-- From this **Matrix** object, you will be able to get various services, including the **AuthenticationService**.
-- With this **AuthenticationService** you will be able to get an existing **Session**, or create one using a **LoginWizard** or a **RegistrationWizard**, which will finally give you a **Session**.
-- From the **Session**, you will be able to retrieve many Services, including the **RoomService**.
-- From the **RoomService**, you will be able to list the rooms, create a **Room**, and get a specific **Room**.
-- And from a **Room**, you will be able to do many things, including get a **Timeline**, send messages, etc.
+- **[Matrix](org.matrix.android.sdk.api.Matrix)**: The app will have to create and manage a **[Matrix](org.matrix.android.sdk.api.Matrix)** object.
+- From this **[Matrix](org.matrix.android.sdk.api.Matrix)** object, you will be able to get various services, including the **[AuthenticationService](org.matrix.android.sdk.api.auth.AuthenticationService)**.
+- With this **[AuthenticationService](org.matrix.android.sdk.api.auth.AuthenticationService)** you will be able to get an existing **[Session](org.matrix.android.sdk.api.session.Session)**, or create one using a **[LoginWizard](org.matrix.android.sdk.api.auth.login.LoginWizard)** or a **[RegistrationWizard](org.matrix.android.sdk.api.auth.registration.RegistrationWizard)**, which will finally give you a **[Session](org.matrix.android.sdk.api.session.Session)**.
+- From the **[Session](org.matrix.android.sdk.api.session.Session)**, you will be able to retrieve many Services, including the **[RoomService](org.matrix.android.sdk.api.session.room.RoomService)**.
+- From the **[RoomService](org.matrix.android.sdk.api.session.room.RoomService)**, you will be able to list the rooms, create a **[Room](org.matrix.android.sdk.api.session.room.Room)**, and get a specific **[Room](org.matrix.android.sdk.api.session.room.Room)**.
+- And from a **[Room](org.matrix.android.sdk.api.session.room.Room)**, you will be able to do many things, including get a **[Timeline](org.matrix.android.sdk.api.session.room.timeline.Timeline)**, send messages, etc.
 
 Please read the whole documentation to learn more!
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/PermalinkParserTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/PermalinkParserTest.kt
index b11a538949a151f702bbce3f9da12ae4ece48357..8717b3f7a856e37318373aeb3cd1844dc2a11d99 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/PermalinkParserTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/PermalinkParserTest.kt
@@ -37,7 +37,10 @@ class PermalinkParserTest {
         Assert.assertTrue("Should be parsed as email invite but was ${parsedLink::class.java}", parsedLink is PermalinkData.RoomEmailInviteLink)
         parsedLink as PermalinkData.RoomEmailInviteLink
         Assert.assertEquals("!MRBNLPtFnMAazZVPMO:matrix.org", parsedLink.roomId)
-        Assert.assertEquals("XmOwRZnSFabCRhTywFbJWKXWVNPysOpXIbroMGaUymqkJSvHeVKRsjHajwjCYdBsvGSvHauxbKfJmOxtXldtyLnyBMLKpBQCMzyYggrdapbVIceWZBtmslOQrXLABRoe", parsedLink.token)
+        Assert.assertEquals(
+                "XmOwRZnSFabCRhTywFbJWKXWVNPysOpXIbroMGaUymqkJSvHeVKRsjHajwjCYdBsvGSvHauxbKfJmOxtXldtyLnyBMLKpBQCMzyYggrdapbVIceWZBtmslOQrXLABRoe",
+                parsedLink.token
+        )
         Assert.assertEquals("vector.im", parsedLink.identityServer)
         Assert.assertEquals("Team2", parsedLink.roomName)
         Assert.assertEquals("hiphop5", parsedLink.inviterName)
@@ -45,7 +48,8 @@ class PermalinkParserTest {
 
     @Test
     fun testParseLinkWIthEvent() {
-        val rawInvite = "https://matrix.to/#/!OGEhHVWSdvArJzumhm:matrix.org/\$xuvJUVDJnwEeVjPx029rAOZ50difpmU_5gZk_T0jGfc?via=matrix.org&via=libera.chat&via=matrix.example.io"
+        val rawInvite =
+                "https://matrix.to/#/!OGEhHVWSdvArJzumhm:matrix.org/\$xuvJUVDJnwEeVjPx029rAOZ50difpmU_5gZk_T0jGfc?via=matrix.org&via=libera.chat&via=matrix.example.io"
 
         val parsedLink = PermalinkParser.parse(rawInvite)
         Assert.assertTrue("Should be parsed as room link", parsedLink is PermalinkData.RoomLink)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/SingleThreadCoroutineDispatcher.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/SingleThreadCoroutineDispatcher.kt
index 3e3af10799a4d07daa6395ad1c96af33fcf9032b..a44cd6c80f9485d5b3773b31803eae9bf6c6b913 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/SingleThreadCoroutineDispatcher.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/SingleThreadCoroutineDispatcher.kt
@@ -21,5 +21,7 @@ import kotlinx.coroutines.asCoroutineDispatcher
 import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
 import java.util.concurrent.Executors
 
-internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main,
-        Executors.newSingleThreadExecutor().asCoroutineDispatcher())
+internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(
+        Main, Main, Main, Main,
+        Executors.newSingleThreadExecutor().asCoroutineDispatcher()
+)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt
index 52dbfc7155b53f10b188dd845a02ee486efc2b26..d2dfe4d9454b2f02d44602a39b185398deb29054 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt
@@ -67,9 +67,11 @@ class DeactivateAccountTest : InstrumentedTest {
         val throwable = commonTestHelper.logAccountWithError(session.myUserId, TestConstants.PASSWORD)
 
         // Test the error
-        assertTrue(throwable is Failure.ServerError &&
-                throwable.error.code == MatrixError.M_USER_DEACTIVATED &&
-                throwable.error.message == "This account has been deactivated")
+        assertTrue(
+                throwable is Failure.ServerError &&
+                        throwable.error.code == MatrixError.M_USER_DEACTIVATED &&
+                        throwable.error.message == "This account has been deactivated"
+        )
 
         // Try to create an account with the deactivate account user id, it will fail (M_USER_IN_USE)
         val hs = commonTestHelper.createHomeServerConfig()
@@ -95,8 +97,10 @@ class DeactivateAccountTest : InstrumentedTest {
 
         // Test the error
         accountCreationError.let {
-            assertTrue(it is Failure.ServerError &&
-                    it.error.code == MatrixError.M_USER_IN_USE)
+            assertTrue(
+                    it is Failure.ServerError &&
+                            it.error.code == MatrixError.M_USER_IN_USE
+            )
         }
 
         // No need to close the session, it has been deactivated
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt
index 4b9e605cd0a54e068b1c6cdb5bad94e6f228bb18..e33e4faea2920db2b6e75956254bcb42dac6eff5 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt
@@ -63,8 +63,9 @@ class CommonTestHelper(context: Context) {
     fun getTestInterceptor(session: Session): MockOkHttpInterceptor? = TestModule.interceptorForSession(session.sessionId) as? MockOkHttpInterceptor
 
     init {
+        var _matrix: TestMatrix? = null
         UiThreadStatement.runOnUiThread {
-            TestMatrix.initialize(
+            _matrix = TestMatrix(
                     context,
                     MatrixConfiguration(
                             applicationFlavor = "TestFlavor",
@@ -72,7 +73,7 @@ class CommonTestHelper(context: Context) {
                     )
             )
         }
-        matrix = TestMatrix.getInstance()
+        matrix = _matrix!!
     }
 
     fun createAccount(userNamePrefix: String, testParams: SessionTestParams): Session {
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt
index 058b1f79338237569877e21ee8c255e0a0987e90..348841313b5f9f5fd6f73d9f551a0c1edfc80f79 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt
@@ -19,6 +19,7 @@ package org.matrix.android.sdk.common
 import android.os.SystemClock
 import android.util.Log
 import androidx.lifecycle.Observer
+import org.amshove.kluent.fail
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertNotNull
 import org.junit.Assert.assertNull
@@ -31,8 +32,16 @@ import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
 import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
 import org.matrix.android.sdk.api.extensions.orFalse
 import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.crypto.MXCryptoError
+import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
+import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
+import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
+import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
 import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupAuthData
 import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
+import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromRecoveryKey
+import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
 import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction
 import org.matrix.android.sdk.api.session.crypto.verification.OutgoingSasVerificationTransaction
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
@@ -40,13 +49,19 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxStat
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.toContent
+import org.matrix.android.sdk.api.session.events.model.toModel
 import org.matrix.android.sdk.api.session.getRoom
 import org.matrix.android.sdk.api.session.room.Room
 import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
+import org.matrix.android.sdk.api.session.room.model.message.MessageContent
 import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
+import org.matrix.android.sdk.api.session.securestorage.EmptyKeySigner
+import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService
 import org.matrix.android.sdk.api.util.Optional
+import org.matrix.android.sdk.api.util.awaitCallback
+import org.matrix.android.sdk.api.util.toBase64NoPadding
 import java.util.UUID
 import kotlin.coroutines.Continuation
 import kotlin.coroutines.resume
@@ -188,17 +203,49 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
         val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!!
 
         // Alice sends a message
-        testHelper.sendTextMessage(roomFromAlicePOV, messagesFromAlice[0], 1)
+        testHelper.sendTextMessage(roomFromAlicePOV, messagesFromAlice[0], 1).first().eventId.let { sentEventId ->
+            // ensure bob got it
+            ensureEventReceived(aliceRoomId, sentEventId, bobSession, true)
+        }
 
         // Bob send 3 messages
-        testHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[0], 1)
-        testHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[1], 1)
-        testHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[2], 1)
+        testHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[0], 1).first().eventId.let { sentEventId ->
+            // ensure alice got it
+            ensureEventReceived(aliceRoomId, sentEventId, aliceSession, true)
+        }
+
+        testHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[1], 1).first().eventId.let { sentEventId ->
+            // ensure alice got it
+            ensureEventReceived(aliceRoomId, sentEventId, aliceSession, true)
+        }
+        testHelper.sendTextMessage(roomFromBobPOV, messagesFromBob[2], 1).first().eventId.let { sentEventId ->
+            // ensure alice got it
+            ensureEventReceived(aliceRoomId, sentEventId, aliceSession, true)
+        }
+
         // Alice sends a message
-        testHelper.sendTextMessage(roomFromAlicePOV, messagesFromAlice[1], 1)
+        testHelper.sendTextMessage(roomFromAlicePOV, messagesFromAlice[1], 1).first().eventId.let { sentEventId ->
+            // ensure bob got it
+            ensureEventReceived(aliceRoomId, sentEventId, bobSession, true)
+        }
         return cryptoTestData
     }
 
+    private fun ensureEventReceived(roomId: String, eventId: String, session: Session, andCanDecrypt: Boolean) {
+        testHelper.waitWithLatch { latch ->
+            testHelper.retryPeriodicallyWithLatch(latch) {
+                val timeLineEvent = session.getRoom(roomId)?.timelineService()?.getTimelineEvent(eventId)
+                if (andCanDecrypt) {
+                    timeLineEvent != null &&
+                            timeLineEvent.isEncrypted() &&
+                            timeLineEvent.root.getClearType() == EventType.MESSAGE
+                } else {
+                    timeLineEvent != null
+                }
+            }
+        }
+    }
+
     fun checkEncryptedEvent(event: Event, roomId: String, clearMessage: String, senderSession: Session) {
         assertEquals(EventType.ENCRYPTED, event.type)
         assertNotNull(event.content)
@@ -291,7 +338,61 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
                                             )
                                     )
                                 }
-                            }, it)
+                            }, it
+                    )
+        }
+    }
+
+    /**
+     * Initialize cross-signing, set up megolm backup and save all in 4S
+     */
+    fun bootstrapSecurity(session: Session) {
+        initializeCrossSigning(session)
+        val ssssService = session.sharedSecretStorageService()
+        testHelper.runBlockingTest {
+            val keyInfo = ssssService.generateKey(
+                    UUID.randomUUID().toString(),
+                    null,
+                    "ssss_key",
+                    EmptyKeySigner()
+            )
+            ssssService.setDefaultKey(keyInfo.keyId)
+
+            ssssService.storeSecret(
+                    MASTER_KEY_SSSS_NAME,
+                    session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.master!!,
+                    listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec))
+            )
+
+            ssssService.storeSecret(
+                    SELF_SIGNING_KEY_SSSS_NAME,
+                    session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.selfSigned!!,
+                    listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec))
+            )
+
+            ssssService.storeSecret(
+                    USER_SIGNING_KEY_SSSS_NAME,
+                    session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.user!!,
+                    listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec))
+            )
+
+            // set up megolm backup
+            val creationInfo = awaitCallback<MegolmBackupCreationInfo> {
+                session.cryptoService().keysBackupService().prepareKeysBackupVersion(null, null, it)
+            }
+            val version = awaitCallback<KeysVersion> {
+                session.cryptoService().keysBackupService().createKeysBackupVersion(creationInfo, it)
+            }
+            // Save it for gossiping
+            session.cryptoService().keysBackupService().saveBackupRecoveryKey(creationInfo.recoveryKey, version = version.version)
+
+            extractCurveKeyFromRecoveryKey(creationInfo.recoveryKey)?.toBase64NoPadding()?.let { secret ->
+                ssssService.storeSecret(
+                        KEYBACKUP_SECRET_SSSS_NAME,
+                        secret,
+                        listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec))
+                )
+            }
         }
     }
 
@@ -299,28 +400,37 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
         assertTrue(alice.cryptoService().crossSigningService().canCrossSign())
         assertTrue(bob.cryptoService().crossSigningService().canCrossSign())
 
-        val requestID = UUID.randomUUID().toString()
         val aliceVerificationService = alice.cryptoService().verificationService()
         val bobVerificationService = bob.cryptoService().verificationService()
 
-        aliceVerificationService.beginKeyVerificationInDMs(
-                VerificationMethod.SAS,
-                requestID,
-                roomId,
-                bob.myUserId,
-                bob.sessionParams.credentials.deviceId!!)
+        val localId = UUID.randomUUID().toString()
+        aliceVerificationService.requestKeyVerificationInDMs(
+                localId = localId,
+                methods = listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SCAN, VerificationMethod.QR_CODE_SHOW),
+                otherUserId = bob.myUserId,
+                roomId = roomId
+        ).transactionId
 
-        // we should reach SHOW SAS on both
-        var alicePovTx: OutgoingSasVerificationTransaction? = null
-        var bobPovTx: IncomingSasVerificationTransaction? = null
+        testHelper.waitWithLatch {
+            testHelper.retryPeriodicallyWithLatch(it) {
+                bobVerificationService.getExistingVerificationRequests(alice.myUserId).firstOrNull {
+                    it.requestInfo?.fromDevice == alice.sessionParams.deviceId
+                } != null
+            }
+        }
+        val incomingRequest = bobVerificationService.getExistingVerificationRequests(alice.myUserId).first {
+            it.requestInfo?.fromDevice == alice.sessionParams.deviceId
+        }
+        bobVerificationService.readyPendingVerification(listOf(VerificationMethod.SAS), alice.myUserId, incomingRequest.transactionId!!)
 
-        // wait for alice to get the ready
+        var requestID: String? = null
+        // wait for it to be readied
         testHelper.waitWithLatch {
             testHelper.retryPeriodicallyWithLatch(it) {
-                bobPovTx = bobVerificationService.getExistingTransaction(alice.myUserId, requestID) as? IncomingSasVerificationTransaction
-                Log.v("TEST", "== bobPovTx is ${alicePovTx?.uxState}")
-                if (bobPovTx?.state == VerificationTxState.OnStarted) {
-                    bobPovTx?.performAccept()
+                val outgoingRequest = aliceVerificationService.getExistingVerificationRequests(bob.myUserId)
+                        .firstOrNull { it.localId == localId }
+                if (outgoingRequest?.isReady == true) {
+                    requestID = outgoingRequest.transactionId!!
                     true
                 } else {
                     false
@@ -328,9 +438,21 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
             }
         }
 
+        aliceVerificationService.beginKeyVerificationInDMs(
+                VerificationMethod.SAS,
+                requestID!!,
+                roomId,
+                bob.myUserId,
+                bob.sessionParams.credentials.deviceId!!
+        )
+
+        // we should reach SHOW SAS on both
+        var alicePovTx: OutgoingSasVerificationTransaction? = null
+        var bobPovTx: IncomingSasVerificationTransaction? = null
+
         testHelper.waitWithLatch {
             testHelper.retryPeriodicallyWithLatch(it) {
-                alicePovTx = aliceVerificationService.getExistingTransaction(bob.myUserId, requestID) as? OutgoingSasVerificationTransaction
+                alicePovTx = aliceVerificationService.getExistingTransaction(bob.myUserId, requestID!!) as? OutgoingSasVerificationTransaction
                 Log.v("TEST", "== alicePovTx is ${alicePovTx?.uxState}")
                 alicePovTx?.state == VerificationTxState.ShortCodeReady
             }
@@ -338,7 +460,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
         // wait for alice to get the ready
         testHelper.waitWithLatch {
             testHelper.retryPeriodicallyWithLatch(it) {
-                bobPovTx = bobVerificationService.getExistingTransaction(alice.myUserId, requestID) as? IncomingSasVerificationTransaction
+                bobPovTx = bobVerificationService.getExistingTransaction(alice.myUserId, requestID!!) as? IncomingSasVerificationTransaction
                 Log.v("TEST", "== bobPovTx is ${alicePovTx?.uxState}")
                 if (bobPovTx?.state == VerificationTxState.OnStarted) {
                     bobPovTx?.performAccept()
@@ -390,4 +512,50 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
 
         return CryptoTestData(roomId, sessions)
     }
+
+    fun ensureCanDecrypt(sentEventIds: List<String>, session: Session, e2eRoomID: String, messagesText: List<String>) {
+        sentEventIds.forEachIndexed { index, sentEventId ->
+            testHelper.waitWithLatch { latch ->
+                testHelper.retryPeriodicallyWithLatch(latch) {
+                    val event = session.getRoom(e2eRoomID)!!.timelineService().getTimelineEvent(sentEventId)!!.root
+                    testHelper.runBlockingTest {
+                        try {
+                            session.cryptoService().decryptEvent(event, "").let { result ->
+                                event.mxDecryptionResult = OlmDecryptionResult(
+                                        payload = result.clearEvent,
+                                        senderKey = result.senderCurve25519Key,
+                                        keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
+                                        forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
+                                )
+                            }
+                        } catch (error: MXCryptoError) {
+                            // nop
+                        }
+                    }
+                    Log.v("TEST", "ensureCanDecrypt ${event.getClearType()} is ${event.getClearContent()}")
+                    event.getClearType() == EventType.MESSAGE &&
+                            messagesText[index] == event.getClearContent()?.toModel<MessageContent>()?.body
+                }
+            }
+        }
+    }
+
+    fun ensureCannotDecrypt(sentEventIds: List<String>, session: Session, e2eRoomID: String, expectedError: MXCryptoError.ErrorType? = null) {
+        sentEventIds.forEach { sentEventId ->
+            val event = session.getRoom(e2eRoomID)!!.timelineService().getTimelineEvent(sentEventId)!!.root
+            testHelper.runBlockingTest {
+                try {
+                    session.cryptoService().decryptEvent(event, "")
+                    fail("Should not be able to decrypt event")
+                } catch (error: MXCryptoError) {
+                    val errorType = (error as? MXCryptoError.Base)?.errorType
+                    if (expectedError == null) {
+                        assertNotNull(errorType)
+                    } else {
+                        assertEquals("Unexpected reason", expectedError, errorType)
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrix.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrix.kt
index fa44167a8f37f1403a321a03ebdb669a6a11d7d0..e663cc186571b539fbde872f1c10331c1aec5f37 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrix.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrix.kt
@@ -38,13 +38,12 @@ import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
 import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory
 import org.matrix.olm.OlmManager
 import java.util.concurrent.Executors
-import java.util.concurrent.atomic.AtomicBoolean
 import javax.inject.Inject
 
 /**
  * This mimics the Matrix class but using TestMatrixComponent internally instead of regular MatrixComponent.
  */
-internal class TestMatrix constructor(context: Context, matrixConfiguration: MatrixConfiguration) {
+internal class TestMatrix(context: Context, matrixConfiguration: MatrixConfiguration) {
 
     @Inject internal lateinit var legacySessionImporter: LegacySessionImporter
     @Inject internal lateinit var authenticationService: AuthenticationService
@@ -60,13 +59,14 @@ internal class TestMatrix constructor(context: Context, matrixConfiguration: Mat
     private val uiHandler = Handler(Looper.getMainLooper())
 
     init {
-        Monarchy.init(context)
-        DaggerTestMatrixComponent.factory().create(context, matrixConfiguration).inject(this)
+        val appContext = context.applicationContext
+        Monarchy.init(appContext)
+        DaggerTestMatrixComponent.factory().create(appContext, matrixConfiguration).inject(this)
         val configuration = Configuration.Builder()
                 .setExecutor(Executors.newCachedThreadPool())
                 .setWorkerFactory(matrixWorkerFactory)
                 .build()
-        WorkManager.initialize(context, configuration)
+        WorkManager.initialize(appContext, configuration)
         uiHandler.post {
             ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
         }
@@ -95,23 +95,6 @@ internal class TestMatrix constructor(context: Context, matrixConfiguration: Mat
     }
 
     companion object {
-
-        private lateinit var instance: TestMatrix
-        private val isInit = AtomicBoolean(false)
-
-        fun initialize(context: Context, matrixConfiguration: MatrixConfiguration) {
-            if (isInit.compareAndSet(false, true)) {
-                instance = TestMatrix(context.applicationContext, matrixConfiguration)
-            }
-        }
-
-        fun getInstance(): TestMatrix {
-            if (isInit.compareAndSet(false, false)) {
-                throw IllegalStateException("Matrix is not initialized properly. You should call TestMatrix.initialize first")
-            }
-            return instance
-        }
-
         fun getSdkVersion(): String {
             return BuildConfig.SDK_VERSION + " (" + BuildConfig.GIT_SDK_REVISION + ")"
         }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt
index dc58339498c720c4d211b5e112d1517eb610d5be..525e168cf1f2a19170d74ba0547a4551e70ff23e 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt
@@ -29,15 +29,17 @@ import org.matrix.android.sdk.internal.raw.RawModule
 import org.matrix.android.sdk.internal.settings.SettingsModule
 import org.matrix.android.sdk.internal.util.system.SystemModule
 
-@Component(modules = [
-    TestModule::class,
-    MatrixModule::class,
-    NetworkModule::class,
-    AuthModule::class,
-    RawModule::class,
-    SettingsModule::class,
-    SystemModule::class
-])
+@Component(
+        modules = [
+            TestModule::class,
+            MatrixModule::class,
+            NetworkModule::class,
+            AuthModule::class,
+            RawModule::class,
+            SettingsModule::class,
+            SystemModule::class
+        ]
+)
 @MatrixScope
 internal interface TestMatrixComponent : MatrixComponent {
 
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreTest.kt
index 3f75aa09798a476184cf35bd170a73b318e17b47..e823aa39a1115124acc2daf9d9918e4a834a3bd6 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreTest.kt
@@ -76,9 +76,11 @@ class CryptoStoreTest : InstrumentedTest {
         }
 
         val olmSession1 = OlmSession().apply {
-            initOutboundSession(olmAccount1,
+            initOutboundSession(
+                    olmAccount1,
                     olmAccount1.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY],
-                    olmAccount1.oneTimeKeys()[OlmAccount.JSON_KEY_ONE_TIME_KEY]?.values?.first())
+                    olmAccount1.oneTimeKeys()[OlmAccount.JSON_KEY_ONE_TIME_KEY]?.values?.first()
+            )
         }
 
         val sessionId1 = olmSession1.sessionIdentifier()
@@ -93,9 +95,11 @@ class CryptoStoreTest : InstrumentedTest {
         }
 
         val olmSession2 = OlmSession().apply {
-            initOutboundSession(olmAccount2,
+            initOutboundSession(
+                    olmAccount2,
                     olmAccount2.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY],
-                    olmAccount2.oneTimeKeys()[OlmAccount.JSON_KEY_ONE_TIME_KEY]?.values?.first())
+                    olmAccount2.oneTimeKeys()[OlmAccount.JSON_KEY_ONE_TIME_KEY]?.values?.first()
+            )
         }
 
         val sessionId2 = olmSession2.sessionIdentifier()
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt
index 88d99f12e062237540b28fed1cff3ae2e952a176..ebe4c5ff6fb52e2408650ed722173309a4236712 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt
@@ -30,13 +30,21 @@ import org.junit.runners.MethodSorters
 import org.matrix.android.sdk.InstrumentedTest
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.crypto.MXCryptoError
+import org.matrix.android.sdk.api.session.crypto.RequestResult
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
 import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
+import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
 import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
-import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
+import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction
+import org.matrix.android.sdk.api.session.crypto.verification.OutgoingSasVerificationTransaction
+import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
+import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
+import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
+import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
+import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
 import org.matrix.android.sdk.api.session.events.model.toModel
 import org.matrix.android.sdk.api.session.getRoom
 import org.matrix.android.sdk.api.session.getRoomSummary
@@ -52,15 +60,13 @@ import org.matrix.android.sdk.common.CryptoTestHelper
 import org.matrix.android.sdk.common.SessionTestParams
 import org.matrix.android.sdk.common.TestConstants
 import org.matrix.android.sdk.common.TestMatrixCallback
+import java.util.concurrent.CountDownLatch
 
 @RunWith(JUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
 @LargeTest
 class E2eeSanityTests : InstrumentedTest {
 
-    private val testHelper = CommonTestHelper(context())
-    private val cryptoTestHelper = CryptoTestHelper(testHelper)
-
     /**
      * Simple test that create an e2ee room.
      * Some new members are added, and a message is sent.
@@ -72,16 +78,24 @@ class E2eeSanityTests : InstrumentedTest {
      */
     @Test
     fun testSendingE2EEMessages() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
         val aliceSession = cryptoTestData.firstSession
         val e2eRoomID = cryptoTestData.roomId
 
         val aliceRoomPOV = aliceSession.getRoom(e2eRoomID)!!
+        // we want to disable key gossiping to just check initial sending of keys
+        aliceSession.cryptoService().enableKeyGossiping(false)
+        cryptoTestData.secondSession?.cryptoService()?.enableKeyGossiping(false)
 
         // add some more users and invite them
         val otherAccounts = listOf("benoit", "valere", "ganfra") // , "adam", "manu")
                 .map {
-                    testHelper.createAccount(it, SessionTestParams(true))
+                    testHelper.createAccount(it, SessionTestParams(true)).also {
+                        it.cryptoService().enableKeyGossiping(false)
+                    }
                 }
 
         Log.v("#E2E TEST", "All accounts created")
@@ -95,18 +109,18 @@ class E2eeSanityTests : InstrumentedTest {
 
         // All user should accept invite
         otherAccounts.forEach { otherSession ->
-            waitForAndAcceptInviteInRoom(otherSession, e2eRoomID)
+            waitForAndAcceptInviteInRoom(testHelper, otherSession, e2eRoomID)
             Log.v("#E2E TEST", "${otherSession.myUserId} joined room $e2eRoomID")
         }
 
         // check that alice see them as joined (not really necessary?)
-        ensureMembersHaveJoined(aliceSession, otherAccounts, e2eRoomID)
+        ensureMembersHaveJoined(testHelper, aliceSession, otherAccounts, e2eRoomID)
 
         Log.v("#E2E TEST", "All users have joined the room")
         Log.v("#E2E TEST", "Alice is sending the message")
 
         val text = "This is my message"
-        val sentEventId: String? = sendMessageInRoom(aliceRoomPOV, text)
+        val sentEventId: String? = sendMessageInRoom(testHelper, aliceRoomPOV, text)
         //        val sentEvent = testHelper.sendTextMessage(aliceRoomPOV, "Hello all", 1).first()
         Assert.assertTrue("Message should be sent", sentEventId != null)
 
@@ -114,10 +128,10 @@ class E2eeSanityTests : InstrumentedTest {
         otherAccounts.forEach { otherSession ->
             testHelper.waitWithLatch { latch ->
                 testHelper.retryPeriodicallyWithLatch(latch) {
-                    val timelineEvent = otherSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEventId!!)
-                    timelineEvent != null &&
-                            timelineEvent.isEncrypted() &&
-                            timelineEvent.root.getClearType() == EventType.MESSAGE
+                    val timeLineEvent = otherSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEventId!!)
+                    timeLineEvent != null &&
+                            timeLineEvent.isEncrypted() &&
+                            timeLineEvent.root.getClearType() == EventType.MESSAGE
                 }
             }
         }
@@ -136,10 +150,10 @@ class E2eeSanityTests : InstrumentedTest {
         }
 
         newAccount.forEach {
-            waitForAndAcceptInviteInRoom(it, e2eRoomID)
+            waitForAndAcceptInviteInRoom(testHelper, it, e2eRoomID)
         }
 
-        ensureMembersHaveJoined(aliceSession, newAccount, e2eRoomID)
+        ensureMembersHaveJoined(testHelper, aliceSession, newAccount, e2eRoomID)
 
         // wait a bit
         testHelper.runBlockingTest {
@@ -164,7 +178,7 @@ class E2eeSanityTests : InstrumentedTest {
         Log.v("#E2E TEST", "Alice sends a new message")
 
         val secondMessage = "2 This is my message"
-        val secondSentEventId: String? = sendMessageInRoom(aliceRoomPOV, secondMessage)
+        val secondSentEventId: String? = sendMessageInRoom(testHelper, aliceRoomPOV, secondMessage)
 
         // new members should be able to decrypt it
         newAccount.forEach { otherSession ->
@@ -188,6 +202,14 @@ class E2eeSanityTests : InstrumentedTest {
         cryptoTestData.cleanUp(testHelper)
     }
 
+    @Test
+    fun testKeyGossipingIsEnabledByDefault() {
+        val testHelper = CommonTestHelper(context())
+        val session = testHelper.createAccount("alice", SessionTestParams(true))
+        Assert.assertTrue("Key gossiping should be enabled by default", session.cryptoService().isKeyGossipingEnabled())
+        testHelper.signOutAndClose(session)
+    }
+
     /**
      * Quick test for basic key backup
      * 1. Create e2e between Alice and Bob
@@ -204,6 +226,9 @@ class E2eeSanityTests : InstrumentedTest {
      */
     @Test
     fun testBasicBackupImport() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
         val aliceSession = cryptoTestData.firstSession
         val bobSession = cryptoTestData.secondSession!!
@@ -227,16 +252,16 @@ class E2eeSanityTests : InstrumentedTest {
         val sentEventIds = mutableListOf<String>()
         val messagesText = listOf("1. Hello", "2. Bob", "3. Good morning")
         messagesText.forEach { text ->
-            val sentEventId = sendMessageInRoom(aliceRoomPOV, text)!!.also {
+            val sentEventId = sendMessageInRoom(testHelper, aliceRoomPOV, text)!!.also {
                 sentEventIds.add(it)
             }
 
             testHelper.waitWithLatch { latch ->
                 testHelper.retryPeriodicallyWithLatch(latch) {
-                    val timelineEvent = bobSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEventId)
-                    timelineEvent != null &&
-                            timelineEvent.isEncrypted() &&
-                            timelineEvent.root.getClearType() == EventType.MESSAGE
+                    val timeLineEvent = bobSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEventId)
+                    timeLineEvent != null &&
+                            timeLineEvent.isEncrypted() &&
+                            timeLineEvent.root.getClearType() == EventType.MESSAGE
                 }
             }
             // we want more so let's discard the session
@@ -289,28 +314,31 @@ class E2eeSanityTests : InstrumentedTest {
             }
         }
         // after initial sync events are not decrypted, so we have to try manually
-        ensureCannotDecrypt(sentEventIds, newBobSession, e2eRoomID, MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID)
+        cryptoTestHelper.ensureCannotDecrypt(sentEventIds, newBobSession, e2eRoomID, MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID)
 
         // Let's now import keys from backup
 
-        newBobSession.cryptoService().keysBackupService().let { keysBackupService ->
+        newBobSession.cryptoService().keysBackupService().let { kbs ->
             val keyVersionResult = testHelper.doSync<KeysVersionResult?> {
-                keysBackupService.getVersion(version.version, it)
+                kbs.getVersion(version.version, it)
             }
 
             val importedResult = testHelper.doSync<ImportRoomKeysResult> {
-                keysBackupService.restoreKeyBackupWithPassword(keyVersionResult!!,
+                kbs.restoreKeyBackupWithPassword(
+                        keyVersionResult!!,
                         keyBackupPassword,
                         null,
                         null,
-                        null, it)
+                        null,
+                        it
+                )
             }
 
             assertEquals(3, importedResult.totalNumberOfKeys)
         }
 
         // ensure bob can now decrypt
-        ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText)
+        cryptoTestHelper.ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText)
 
         testHelper.signOutAndClose(newBobSession)
     }
@@ -321,6 +349,9 @@ class E2eeSanityTests : InstrumentedTest {
      */
     @Test
     fun testSimpleGossip() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
         val aliceSession = cryptoTestData.firstSession
         val bobSession = cryptoTestData.secondSession!!
@@ -328,30 +359,28 @@ class E2eeSanityTests : InstrumentedTest {
 
         val aliceRoomPOV = aliceSession.getRoom(e2eRoomID)!!
 
-        cryptoTestHelper.initializeCrossSigning(bobSession)
-
         // let's send a few message to bob
         val sentEventIds = mutableListOf<String>()
         val messagesText = listOf("1. Hello", "2. Bob")
 
         Log.v("#E2E TEST", "Alice sends some messages")
         messagesText.forEach { text ->
-            val sentEventId = sendMessageInRoom(aliceRoomPOV, text)!!.also {
+            val sentEventId = sendMessageInRoom(testHelper, aliceRoomPOV, text)!!.also {
                 sentEventIds.add(it)
             }
 
             testHelper.waitWithLatch { latch ->
                 testHelper.retryPeriodicallyWithLatch(latch) {
-                    val timelineEvent = bobSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEventId)
-                    timelineEvent != null &&
-                            timelineEvent.isEncrypted() &&
-                            timelineEvent.root.getClearType() == EventType.MESSAGE
+                    val timeLineEvent = bobSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEventId)
+                    timeLineEvent != null &&
+                            timeLineEvent.isEncrypted() &&
+                            timeLineEvent.root.getClearType() == EventType.MESSAGE
                 }
             }
         }
 
         // Ensure bob can decrypt
-        ensureIsDecrypted(sentEventIds, bobSession, e2eRoomID)
+        ensureIsDecrypted(testHelper, sentEventIds, bobSession, e2eRoomID)
 
         // Let's now add a new bob session
         // Create a new session for bob
@@ -361,7 +390,11 @@ class E2eeSanityTests : InstrumentedTest {
         // check that new bob can't currently decrypt
         Log.v("#E2E TEST", "check that new bob can't currently decrypt")
 
-        ensureCannotDecrypt(sentEventIds, newBobSession, e2eRoomID, MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID)
+        cryptoTestHelper.ensureCannotDecrypt(sentEventIds, newBobSession, e2eRoomID, null)
+//        newBobSession.cryptoService().getOutgoingRoomKeyRequests()
+//                .firstOrNull {
+//                    it.sessionId ==
+//                }
 
         // Try to request
         sentEventIds.forEach { sentEventId ->
@@ -370,12 +403,34 @@ class E2eeSanityTests : InstrumentedTest {
         }
 
         // wait a bit
-        testHelper.runBlockingTest {
-            delay(10_000)
-        }
+        // we need to wait a couple of syncs to let sharing occurs
+//        testHelper.waitFewSyncs(newBobSession, 6)
 
         // Ensure that new bob still can't decrypt (keys must have been withheld)
-        ensureCannotDecrypt(sentEventIds, newBobSession, e2eRoomID, MXCryptoError.ErrorType.KEYS_WITHHELD)
+        sentEventIds.forEach { sentEventId ->
+            val megolmSessionId = newBobSession.getRoom(e2eRoomID)!!
+                    .getTimelineEvent(sentEventId)!!
+                    .root.content.toModel<EncryptedEventContent>()!!.sessionId
+            testHelper.waitWithLatch { latch ->
+                testHelper.retryPeriodicallyWithLatch(latch) {
+                    val aliceReply = newBobSession.cryptoService().getOutgoingRoomKeyRequests()
+                            .first {
+                                it.sessionId == megolmSessionId &&
+                                        it.roomId == e2eRoomID
+                            }
+                            .results.also {
+                                Log.w("##TEST", "result list is $it")
+                            }
+                            .firstOrNull { it.userId == aliceSession.myUserId }
+                            ?.result
+                    aliceReply != null &&
+                            aliceReply is RequestResult.Failure &&
+                            WithHeldCode.UNAUTHORISED == aliceReply.code
+                }
+            }
+        }
+
+        cryptoTestHelper.ensureCannotDecrypt(sentEventIds, newBobSession, e2eRoomID, null)
 
         // Now mark new bob session as verified
 
@@ -388,12 +443,7 @@ class E2eeSanityTests : InstrumentedTest {
             newBobSession.cryptoService().reRequestRoomKeyForEvent(event)
         }
 
-        // wait a bit
-        testHelper.runBlockingTest {
-            delay(10_000)
-        }
-
-        ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText)
+        cryptoTestHelper.ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText)
 
         cryptoTestData.cleanUp(testHelper)
         testHelper.signOutAndClose(newBobSession)
@@ -404,6 +454,9 @@ class E2eeSanityTests : InstrumentedTest {
      */
     @Test
     fun testForwardBetterKey() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
         val aliceSession = cryptoTestData.firstSession
         val bobSessionWithBetterKey = cryptoTestData.secondSession!!
@@ -411,35 +464,33 @@ class E2eeSanityTests : InstrumentedTest {
 
         val aliceRoomPOV = aliceSession.getRoom(e2eRoomID)!!
 
-        cryptoTestHelper.initializeCrossSigning(bobSessionWithBetterKey)
-
         // let's send a few message to bob
         var firstEventId: String
         val firstMessage = "1. Hello"
 
         Log.v("#E2E TEST", "Alice sends some messages")
         firstMessage.let { text ->
-            firstEventId = sendMessageInRoom(aliceRoomPOV, text)!!
+            firstEventId = sendMessageInRoom(testHelper, aliceRoomPOV, text)!!
 
             testHelper.waitWithLatch { latch ->
                 testHelper.retryPeriodicallyWithLatch(latch) {
-                    val timelineEvent = bobSessionWithBetterKey.getRoom(e2eRoomID)?.getTimelineEvent(firstEventId)
-                    timelineEvent != null &&
-                            timelineEvent.isEncrypted() &&
-                            timelineEvent.root.getClearType() == EventType.MESSAGE
+                    val timeLineEvent = bobSessionWithBetterKey.getRoom(e2eRoomID)?.getTimelineEvent(firstEventId)
+                    timeLineEvent != null &&
+                            timeLineEvent.isEncrypted() &&
+                            timeLineEvent.root.getClearType() == EventType.MESSAGE
                 }
             }
         }
 
         // Ensure bob can decrypt
-        ensureIsDecrypted(listOf(firstEventId), bobSessionWithBetterKey, e2eRoomID)
+        ensureIsDecrypted(testHelper, listOf(firstEventId), bobSessionWithBetterKey, e2eRoomID)
 
         // Let's add a new unverified session from bob
         val newBobSession = testHelper.logIntoAccount(bobSessionWithBetterKey.myUserId, SessionTestParams(true))
 
         // check that new bob can't currently decrypt
         Log.v("#E2E TEST", "check that new bob can't currently decrypt")
-        ensureCannotDecrypt(listOf(firstEventId), newBobSession, e2eRoomID, MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID)
+        cryptoTestHelper.ensureCannotDecrypt(listOf(firstEventId), newBobSession, e2eRoomID, null)
 
         // Now let alice send a new message. this time the new bob session will be able to decrypt
         var secondEventId: String
@@ -447,14 +498,14 @@ class E2eeSanityTests : InstrumentedTest {
 
         Log.v("#E2E TEST", "Alice sends some messages")
         secondMessage.let { text ->
-            secondEventId = sendMessageInRoom(aliceRoomPOV, text)!!
+            secondEventId = sendMessageInRoom(testHelper, aliceRoomPOV, text)!!
 
             testHelper.waitWithLatch { latch ->
                 testHelper.retryPeriodicallyWithLatch(latch) {
-                    val timelineEvent = newBobSession.getRoom(e2eRoomID)?.getTimelineEvent(secondEventId)
-                    timelineEvent != null &&
-                            timelineEvent.isEncrypted() &&
-                            timelineEvent.root.getClearType() == EventType.MESSAGE
+                    val timeLineEvent = newBobSession.getRoom(e2eRoomID)?.getTimelineEvent(secondEventId)
+                    timeLineEvent != null &&
+                            timeLineEvent.isEncrypted() &&
+                            timeLineEvent.root.getClearType() == EventType.MESSAGE
                 }
             }
         }
@@ -473,9 +524,7 @@ class E2eeSanityTests : InstrumentedTest {
             try {
                 newBobSession.cryptoService().decryptEvent(firstEventNewBobPov.root, "")
                 fail("Should not be able to decrypt event")
-            } catch (error: MXCryptoError) {
-                val errorType = (error as? MXCryptoError.Base)?.errorType
-                assertEquals(MXCryptoError.ErrorType.UNKNOWN_MESSAGE_INDEX, errorType)
+            } catch (_: MXCryptoError) {
             }
         }
 
@@ -497,41 +546,45 @@ class E2eeSanityTests : InstrumentedTest {
                 .markedLocallyAsManuallyVerified(bobSessionWithBetterKey.myUserId, bobSessionWithBetterKey.sessionParams.deviceId!!)
 
         // now let new session request
-        newBobSession.cryptoService().requestRoomKeyForEvent(firstEventNewBobPov.root)
+        newBobSession.cryptoService().reRequestRoomKeyForEvent(firstEventNewBobPov.root)
 
-        // wait a bit
-        testHelper.runBlockingTest {
-            delay(10_000)
-        }
+        // We need to wait for the key request to be sent out and then a reply to be received
 
         // old session should have shared the key at earliest known index now
         // we should be able to decrypt both
-        testHelper.runBlockingTest {
-            try {
-                newBobSession.cryptoService().decryptEvent(firstEventNewBobPov.root, "")
-            } catch (error: MXCryptoError) {
-                fail("Should be able to decrypt first event now $error")
-            }
-        }
-        testHelper.runBlockingTest {
-            try {
-                newBobSession.cryptoService().decryptEvent(secondEventNewBobPov.root, "")
-            } catch (error: MXCryptoError) {
-                fail("Should be able to decrypt event $error")
+        testHelper.waitWithLatch {
+            testHelper.retryPeriodicallyWithLatch(it) {
+                val canDecryptFirst = try {
+                    testHelper.runBlockingTest {
+                        newBobSession.cryptoService().decryptEvent(firstEventNewBobPov.root, "")
+                    }
+                    true
+                } catch (error: MXCryptoError) {
+                    false
+                }
+                val canDecryptSecond = try {
+                    testHelper.runBlockingTest {
+                        newBobSession.cryptoService().decryptEvent(secondEventNewBobPov.root, "")
+                    }
+                    true
+                } catch (error: MXCryptoError) {
+                    false
+                }
+                canDecryptFirst && canDecryptSecond
             }
         }
 
-        cryptoTestData.cleanUp(testHelper)
+        testHelper.signOutAndClose(aliceSession)
+        testHelper.signOutAndClose(bobSessionWithBetterKey)
         testHelper.signOutAndClose(newBobSession)
     }
 
-    private fun sendMessageInRoom(aliceRoomPOV: Room, text: String): String? {
+    private fun sendMessageInRoom(testHelper: CommonTestHelper, aliceRoomPOV: Room, text: String): String? {
         aliceRoomPOV.sendService().sendTextMessage(text)
         var sentEventId: String? = null
         testHelper.waitWithLatch(4 * TestConstants.timeOutMillis) { latch ->
             val timeline = aliceRoomPOV.timelineService().createTimeline(null, TimelineSettings(60))
             timeline.start()
-
             testHelper.retryPeriodicallyWithLatch(latch) {
                 val decryptedMsg = timeline.getSnapshot()
                         .filter { it.root.getClearType() == EventType.MESSAGE }
@@ -550,7 +603,157 @@ class E2eeSanityTests : InstrumentedTest {
         return sentEventId
     }
 
-    private fun ensureMembersHaveJoined(aliceSession: Session, otherAccounts: List<Session>, e2eRoomID: String) {
+    /**
+     * Test that if a better key is forwared (lower index, it is then used)
+     */
+    @Test
+    fun testSelfInteractiveVerificationAndGossip() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+
+        val aliceSession = testHelper.createAccount("alice", SessionTestParams(true))
+        cryptoTestHelper.bootstrapSecurity(aliceSession)
+
+        // now let's create a new login from alice
+
+        val aliceNewSession = testHelper.logIntoAccount(aliceSession.myUserId, SessionTestParams(true))
+
+        val oldCompleteLatch = CountDownLatch(1)
+        lateinit var oldCode: String
+        aliceSession.cryptoService().verificationService().addListener(object : VerificationService.Listener {
+
+            override fun verificationRequestUpdated(pr: PendingVerificationRequest) {
+                val readyInfo = pr.readyInfo
+                if (readyInfo != null) {
+                    aliceSession.cryptoService().verificationService().beginKeyVerification(
+                            VerificationMethod.SAS,
+                            aliceSession.myUserId,
+                            readyInfo.fromDevice,
+                            readyInfo.transactionId
+
+                    )
+                }
+            }
+
+            override fun transactionUpdated(tx: VerificationTransaction) {
+                Log.d("##TEST", "exitsingPov: $tx")
+                val sasTx = tx as OutgoingSasVerificationTransaction
+                when (sasTx.uxState) {
+                    OutgoingSasVerificationTransaction.UxState.SHOW_SAS -> {
+                        // for the test we just accept?
+                        oldCode = sasTx.getDecimalCodeRepresentation()
+                        sasTx.userHasVerifiedShortCode()
+                    }
+                    OutgoingSasVerificationTransaction.UxState.VERIFIED -> {
+                        // we can release this latch?
+                        oldCompleteLatch.countDown()
+                    }
+                    else                                                -> Unit
+                }
+            }
+        })
+
+        val newCompleteLatch = CountDownLatch(1)
+        lateinit var newCode: String
+        aliceNewSession.cryptoService().verificationService().addListener(object : VerificationService.Listener {
+
+            override fun verificationRequestCreated(pr: PendingVerificationRequest) {
+                // let's ready
+                aliceNewSession.cryptoService().verificationService().readyPendingVerification(
+                        listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SCAN, VerificationMethod.QR_CODE_SHOW),
+                        aliceSession.myUserId,
+                        pr.transactionId!!
+                )
+            }
+
+            var matchOnce = true
+            override fun transactionUpdated(tx: VerificationTransaction) {
+                Log.d("##TEST", "newPov: $tx")
+
+                val sasTx = tx as IncomingSasVerificationTransaction
+                when (sasTx.uxState) {
+                    IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> {
+                        // no need to accept as there was a request first it will auto accept
+                    }
+                    IncomingSasVerificationTransaction.UxState.SHOW_SAS    -> {
+                        if (matchOnce) {
+                            sasTx.userHasVerifiedShortCode()
+                            newCode = sasTx.getDecimalCodeRepresentation()
+                            matchOnce = false
+                        }
+                    }
+                    IncomingSasVerificationTransaction.UxState.VERIFIED    -> {
+                        newCompleteLatch.countDown()
+                    }
+                    else                                                   -> Unit
+                }
+            }
+        })
+
+        // initiate self verification
+        aliceSession.cryptoService().verificationService().requestKeyVerification(
+                listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SCAN, VerificationMethod.QR_CODE_SHOW),
+                aliceNewSession.myUserId,
+                listOf(aliceNewSession.sessionParams.deviceId!!)
+        )
+        testHelper.await(oldCompleteLatch)
+        testHelper.await(newCompleteLatch)
+        assertEquals("Decimal code should have matched", oldCode, newCode)
+
+        // Assert that devices are verified
+        val newDeviceFromOldPov: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceNewSession.sessionParams.deviceId)
+        val oldDeviceFromNewPov: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceSession.sessionParams.deviceId)
+
+        Assert.assertTrue("new device should be verified from old point of view", newDeviceFromOldPov!!.isVerified)
+        Assert.assertTrue("old device should be verified from new point of view", oldDeviceFromNewPov!!.isVerified)
+
+        // wait for secret gossiping to happen
+        testHelper.waitWithLatch { latch ->
+            testHelper.retryPeriodicallyWithLatch(latch) {
+                aliceNewSession.cryptoService().crossSigningService().allPrivateKeysKnown()
+            }
+        }
+
+        testHelper.waitWithLatch { latch ->
+            testHelper.retryPeriodicallyWithLatch(latch) {
+                aliceNewSession.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo() != null
+            }
+        }
+
+        assertEquals(
+                "MSK Private parts should be the same",
+                aliceSession.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.master,
+                aliceNewSession.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.master
+        )
+        assertEquals(
+                "USK Private parts should be the same",
+                aliceSession.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.user,
+                aliceNewSession.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.user
+        )
+
+        assertEquals(
+                "SSK Private parts should be the same",
+                aliceSession.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.selfSigned,
+                aliceNewSession.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.selfSigned
+        )
+
+        // Let's check that we have the megolm backup key
+        assertEquals(
+                "Megolm key should be the same",
+                aliceSession.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()!!.recoveryKey,
+                aliceNewSession.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()!!.recoveryKey
+        )
+        assertEquals(
+                "Megolm version should be the same",
+                aliceSession.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()!!.version,
+                aliceNewSession.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()!!.version
+        )
+
+        testHelper.signOutAndClose(aliceSession)
+        testHelper.signOutAndClose(aliceNewSession)
+    }
+
+    private fun ensureMembersHaveJoined(testHelper: CommonTestHelper, aliceSession: Session, otherAccounts: List<Session>, e2eRoomID: String) {
         testHelper.waitWithLatch { latch ->
             testHelper.retryPeriodicallyWithLatch(latch) {
                 otherAccounts.map {
@@ -562,7 +765,7 @@ class E2eeSanityTests : InstrumentedTest {
         }
     }
 
-    private fun waitForAndAcceptInviteInRoom(otherSession: Session, e2eRoomID: String) {
+    private fun waitForAndAcceptInviteInRoom(testHelper: CommonTestHelper, otherSession: Session, e2eRoomID: String) {
         testHelper.waitWithLatch { latch ->
             testHelper.retryPeriodicallyWithLatch(latch) {
                 val roomSummary = otherSession.getRoomSummary(e2eRoomID)
@@ -574,7 +777,8 @@ class E2eeSanityTests : InstrumentedTest {
             }
         }
 
-        testHelper.runBlockingTest(60_000) {
+        // not sure why it's taking so long :/
+        testHelper.runBlockingTest(90_000) {
             Log.v("#E2E TEST", "${otherSession.myUserId} tries to join room $e2eRoomID")
             try {
                 otherSession.roomService().joinRoom(e2eRoomID)
@@ -592,59 +796,14 @@ class E2eeSanityTests : InstrumentedTest {
         }
     }
 
-    private fun ensureCanDecrypt(sentEventIds: MutableList<String>, session: Session, e2eRoomID: String, messagesText: List<String>) {
-        sentEventIds.forEachIndexed { index, sentEventId ->
-            testHelper.waitWithLatch { latch ->
-                testHelper.retryPeriodicallyWithLatch(latch) {
-                    val event = session.getRoom(e2eRoomID)!!.getTimelineEvent(sentEventId)!!.root
-                    testHelper.runBlockingTest {
-                        try {
-                            session.cryptoService().decryptEvent(event, "").let { result ->
-                                event.mxDecryptionResult = OlmDecryptionResult(
-                                        payload = result.clearEvent,
-                                        senderKey = result.senderCurve25519Key,
-                                        keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
-                                        forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
-                                )
-                            }
-                        } catch (error: MXCryptoError) {
-                            // nop
-                        }
-                    }
-                    event.getClearType() == EventType.MESSAGE &&
-                            messagesText[index] == event.getClearContent()?.toModel<MessageContent>()?.body
-                }
-            }
-        }
-    }
-
-    private fun ensureIsDecrypted(sentEventIds: List<String>, session: Session, e2eRoomID: String) {
+    private fun ensureIsDecrypted(testHelper: CommonTestHelper, sentEventIds: List<String>, session: Session, e2eRoomID: String) {
         testHelper.waitWithLatch { latch ->
             sentEventIds.forEach { sentEventId ->
                 testHelper.retryPeriodicallyWithLatch(latch) {
-                    val timelineEvent = session.getRoom(e2eRoomID)?.getTimelineEvent(sentEventId)
-                    timelineEvent != null &&
-                            timelineEvent.isEncrypted() &&
-                            timelineEvent.root.getClearType() == EventType.MESSAGE
-                }
-            }
-        }
-    }
-
-    private fun ensureCannotDecrypt(sentEventIds: List<String>, newBobSession: Session, e2eRoomID: String, expectedError: MXCryptoError.ErrorType?) {
-        sentEventIds.forEach { sentEventId ->
-            val event = newBobSession.getRoom(e2eRoomID)!!.getTimelineEvent(sentEventId)!!.root
-            testHelper.runBlockingTest {
-                try {
-                    newBobSession.cryptoService().decryptEvent(event, "")
-                    fail("Should not be able to decrypt event")
-                } catch (error: MXCryptoError) {
-                    val errorType = (error as? MXCryptoError.Base)?.errorType
-                    if (expectedError == null) {
-                        Assert.assertNotNull(errorType)
-                    } else {
-                        assertEquals(expectedError, errorType, "Message expected to be UISI")
-                    }
+                    val timeLineEvent = session.getRoom(e2eRoomID)?.getTimelineEvent(sentEventId)
+                    timeLineEvent != null &&
+                            timeLineEvent.isEncrypted() &&
+                            timeLineEvent.root.getClearType() == EventType.MESSAGE
                 }
             }
         }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ExportEncryptionTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ExportEncryptionTest.kt
index 17664c78aa51afb6df278341d33006c4eb0bf218..c2d8f4fb35f30c99457c8b81c2298d1a29b90763 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ExportEncryptionTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ExportEncryptionTest.kt
@@ -93,9 +93,11 @@ class ExportEncryptionTest {
             fail("## checkExportDecrypt1() failed : " + e.message)
         }
 
-        assertEquals("## checkExportDecrypt1() : expectedString $expectedString -- decodedString $decodedString",
+        assertEquals(
+                "## checkExportDecrypt1() : expectedString $expectedString -- decodedString $decodedString",
                 expectedString,
-                decodedString)
+                decodedString
+        )
     }
 
     @Test
@@ -111,9 +113,11 @@ class ExportEncryptionTest {
             fail("## checkExportDecrypt2() failed : " + e.message)
         }
 
-        assertEquals("## checkExportDecrypt2() : expectedString $expectedString -- decodedString $decodedString",
+        assertEquals(
+                "## checkExportDecrypt2() : expectedString $expectedString -- decodedString $decodedString",
                 expectedString,
-                decodedString)
+                decodedString
+        )
     }
 
     @Test
@@ -129,9 +133,11 @@ class ExportEncryptionTest {
             fail("## checkExportDecrypt3() failed : " + e.message)
         }
 
-        assertEquals("## checkExportDecrypt3() : expectedString $expectedString -- decodedString $decodedString",
+        assertEquals(
+                "## checkExportDecrypt3() : expectedString $expectedString -- decodedString $decodedString",
                 expectedString,
-                decodedString)
+                decodedString
+        )
     }
 
     @Test
@@ -147,9 +153,11 @@ class ExportEncryptionTest {
             fail("## checkExportEncrypt1() failed : " + e.message)
         }
 
-        assertEquals("## checkExportEncrypt1() : expectedString $expectedString -- decodedString $decodedString",
+        assertEquals(
+                "## checkExportEncrypt1() : expectedString $expectedString -- decodedString $decodedString",
                 expectedString,
-                decodedString)
+                decodedString
+        )
     }
 
     @Test
@@ -165,9 +173,11 @@ class ExportEncryptionTest {
             fail("## checkExportEncrypt2() failed : " + e.message)
         }
 
-        assertEquals("## checkExportEncrypt2() : expectedString $expectedString -- decodedString $decodedString",
+        assertEquals(
+                "## checkExportEncrypt2() : expectedString $expectedString -- decodedString $decodedString",
                 expectedString,
-                decodedString)
+                decodedString
+        )
     }
 
     @Test
@@ -183,9 +193,11 @@ class ExportEncryptionTest {
             fail("## checkExportEncrypt3() failed : " + e.message)
         }
 
-        assertEquals("## checkExportEncrypt3() : expectedString $expectedString -- decodedString $decodedString",
+        assertEquals(
+                "## checkExportEncrypt3() : expectedString $expectedString -- decodedString $decodedString",
                 expectedString,
-                decodedString)
+                decodedString
+        )
     }
 
     @Test
@@ -201,8 +213,10 @@ class ExportEncryptionTest {
             fail("## checkExportEncrypt4() failed : " + e.message)
         }
 
-        assertEquals("## checkExportEncrypt4() : expectedString $expectedString -- decodedString $decodedString",
+        assertEquals(
+                "## checkExportEncrypt4() : expectedString $expectedString -- decodedString $decodedString",
                 expectedString,
-                decodedString)
+                decodedString
+        )
     }
 }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt
index 8a1edec5e3dcd9448998992fa801b3f952accac2..93aa78a3050a8cb6e48f5ca288d2d60626fade8c 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt
@@ -27,7 +27,6 @@ import org.junit.runners.MethodSorters
 import org.matrix.android.sdk.InstrumentedTest
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
-import org.matrix.android.sdk.api.session.events.model.content.RoomKeyContent
 import org.matrix.android.sdk.api.session.events.model.toModel
 import org.matrix.android.sdk.api.session.getRoom
 import org.matrix.android.sdk.api.session.room.getTimelineEvent
@@ -51,10 +50,7 @@ class PreShareKeysTest : InstrumentedTest {
         // clear any outbound session
         aliceSession.cryptoService().discardOutboundSession(e2eRoomID)
 
-        val preShareCount = bobSession.cryptoService().getGossipingEvents().count {
-            it.senderId == aliceSession.myUserId &&
-                    it.getClearType() == EventType.ROOM_KEY
-        }
+        val preShareCount = bobSession.cryptoService().keysBackupService().getTotalNumbersOfKeys()
 
         assertEquals("Bob should not have receive any key from alice at this point", 0, preShareCount)
         Log.d("#Test", "Room Key Received from alice $preShareCount")
@@ -66,23 +62,23 @@ class PreShareKeysTest : InstrumentedTest {
 
         testHelper.waitWithLatch { latch ->
             testHelper.retryPeriodicallyWithLatch(latch) {
-                val newGossipCount = bobSession.cryptoService().getGossipingEvents().count {
-                    it.senderId == aliceSession.myUserId &&
-                            it.getClearType() == EventType.ROOM_KEY
-                }
-                newGossipCount > preShareCount
+                val newKeysCount = bobSession.cryptoService().keysBackupService().getTotalNumbersOfKeys()
+                newKeysCount > preShareCount
             }
         }
 
-        val latest = bobSession.cryptoService().getGossipingEvents().lastOrNull {
-            it.senderId == aliceSession.myUserId &&
-                    it.getClearType() == EventType.ROOM_KEY
-        }
+        val aliceCryptoStore = (aliceSession.cryptoService() as DefaultCryptoService).cryptoStoreForTesting
+        val aliceOutboundSessionInRoom = aliceCryptoStore.getCurrentOutboundGroupSessionForRoom(e2eRoomID)!!.outboundGroupSession.sessionIdentifier()
+
+        val bobCryptoStore = (bobSession.cryptoService() as DefaultCryptoService).cryptoStoreForTesting
+        val aliceDeviceBobPov = bobCryptoStore.getUserDevice(aliceSession.myUserId, aliceSession.sessionParams.deviceId!!)!!
+        val bobInboundForAlice = bobCryptoStore.getInboundGroupSession(aliceOutboundSessionInRoom, aliceDeviceBobPov.identityKey()!!)
+        assertNotNull("Bob should have received and decrypted a room key event from alice", bobInboundForAlice)
+        assertEquals("Wrong room", e2eRoomID, bobInboundForAlice!!.roomId)
+
+        val megolmSessionId = bobInboundForAlice.olmInboundGroupSession!!.sessionIdentifier()
 
-        val content = latest?.getClearContent().toModel<RoomKeyContent>()
-        assertNotNull("Bob should have received and decrypted a room key event from alice", content)
-        assertEquals("Wrong room", e2eRoomID, content!!.roomId)
-        val megolmSessionId = content.sessionId!!
+        assertEquals("Wrong session", aliceOutboundSessionInRoom, megolmSessionId)
 
         val sharedIndex = aliceSession.cryptoService().getSharedWithInfo(e2eRoomID, megolmSessionId)
                 .getObject(bobSession.myUserId, bobSession.sessionParams.deviceId)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt
index de4a928dc36f4bedfb079b8cf6c99a05666b1669..0f3a4b4181923e7c032ef4dc96b076f2933e1bd2 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt
@@ -171,7 +171,10 @@ class UnwedgingTest : InstrumentedTest {
         // Let us wedge the session now. Set crypto state like after the first message
         Timber.i("## CRYPTO | testUnwedging: wedge the session now. Set crypto state like after the first message")
 
-        aliceCryptoStore.storeSession(OlmSessionWrapper(deserializeFromRealm<OlmSession>(oldSession)!!), bobSession.cryptoService().getMyDevice().identityKey()!!)
+        aliceCryptoStore.storeSession(
+                OlmSessionWrapper(deserializeFromRealm<OlmSession>(oldSession)!!),
+                bobSession.cryptoService().getMyDevice().identityKey()!!
+        )
         olmDevice.clearOlmSessionCache()
         Thread.sleep(6_000)
 
@@ -218,7 +221,8 @@ class UnwedgingTest : InstrumentedTest {
                                             )
                                     )
                                 }
-                            }, it)
+                            }, it
+                    )
         }
 
         // Wait until we received back the key
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt
index 0f3ff7898fd357c3ceada6d94f14cb873274fe7f..a37626dc20b9bd7bc825def322e6e1287625fbb3 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt
@@ -126,8 +126,16 @@ class XSigningTest : InstrumentedTest {
         assertNull("Alice should not see bob User key", bobKeysFromAlicePOV.userKey())
         assertNotNull("Alice can see bob SelfSigned key", bobKeysFromAlicePOV.selfSigningKey())
 
-        assertEquals("Bob keys from alice pov should match", bobKeysFromAlicePOV.masterKey()?.unpaddedBase64PublicKey, bobSession.cryptoService().crossSigningService().getMyCrossSigningKeys()?.masterKey()?.unpaddedBase64PublicKey)
-        assertEquals("Bob keys from alice pov should match", bobKeysFromAlicePOV.selfSigningKey()?.unpaddedBase64PublicKey, bobSession.cryptoService().crossSigningService().getMyCrossSigningKeys()?.selfSigningKey()?.unpaddedBase64PublicKey)
+        assertEquals(
+                "Bob keys from alice pov should match",
+                bobKeysFromAlicePOV.masterKey()?.unpaddedBase64PublicKey,
+                bobSession.cryptoService().crossSigningService().getMyCrossSigningKeys()?.masterKey()?.unpaddedBase64PublicKey
+        )
+        assertEquals(
+                "Bob keys from alice pov should match",
+                bobKeysFromAlicePOV.selfSigningKey()?.unpaddedBase64PublicKey,
+                bobSession.cryptoService().crossSigningService().getMyCrossSigningKeys()?.selfSigningKey()?.unpaddedBase64PublicKey
+        )
 
         assertFalse("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV.isTrusted())
 
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt
index 592d24fb690650338a44e8e166cb93aee72a29e0..2e4fd62822ba37ca2c43ba3cc9c17497e2f18817 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt
@@ -19,59 +19,45 @@ package org.matrix.android.sdk.internal.crypto.gossiping
 import android.util.Log
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
-import junit.framework.TestCase.assertEquals
 import junit.framework.TestCase.assertNotNull
 import junit.framework.TestCase.assertTrue
 import junit.framework.TestCase.fail
+import org.amshove.kluent.internal.assertEquals
 import org.junit.Assert
+import org.junit.Assert.assertNull
 import org.junit.FixMethodOrder
-import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.matrix.android.sdk.InstrumentedTest
-import org.matrix.android.sdk.api.auth.UIABaseAuth
-import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
-import org.matrix.android.sdk.api.auth.UserPasswordAuth
-import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
-import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState
+import org.matrix.android.sdk.api.session.crypto.RequestResult
 import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
-import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
-import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
-import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
-import org.matrix.android.sdk.api.session.crypto.model.GossipingRequestState
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingGossipingRequestState
-import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction
-import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
-import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
-import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
-import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
-import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
 import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
+import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
 import org.matrix.android.sdk.api.session.events.model.toModel
 import org.matrix.android.sdk.api.session.getRoom
 import org.matrix.android.sdk.api.session.room.getTimelineEvent
 import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
 import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
-import org.matrix.android.sdk.api.session.room.model.message.MessageContent
+import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
 import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.CryptoTestHelper
 import org.matrix.android.sdk.common.SessionTestParams
 import org.matrix.android.sdk.common.TestConstants
-import kotlin.coroutines.Continuation
-import kotlin.coroutines.resume
 
 @RunWith(AndroidJUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
 @LargeTest
 class KeyShareTests : InstrumentedTest {
 
-    private val commonTestHelper = CommonTestHelper(context())
-
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun test_DoNotSelfShareIfNotTrusted() {
+        val commonTestHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+
         val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
+        Log.v("TEST", "=======> AliceSession 1 is ${aliceSession.sessionParams.deviceId}")
 
         // Create an encrypted room and add a message
         val roomId = commonTestHelper.runBlockingTest {
@@ -86,11 +72,18 @@ class KeyShareTests : InstrumentedTest {
         assertNotNull(room)
         Thread.sleep(4_000)
         assertTrue(room?.roomCryptoService()?.isEncrypted() == true)
-        val sentEventId = commonTestHelper.sendTextMessage(room!!, "My Message", 1).first().eventId
 
-        // Open a new sessionx
+        val sentEvent = commonTestHelper.sendTextMessage(room!!, "My Message", 1).first()
+        val sentEventId = sentEvent.eventId
+        val sentEventText = sentEvent.getLastMessageContent()?.body
 
-        val aliceSession2 = commonTestHelper.logIntoAccount(aliceSession.myUserId, SessionTestParams(true))
+        // Open a new session
+        val aliceSession2 = commonTestHelper.logIntoAccount(aliceSession.myUserId, SessionTestParams(false))
+        // block key requesting for now as decrypt will send requests (room summary is trying to decrypt)
+        aliceSession2.cryptoService().enableKeyGossiping(false)
+        commonTestHelper.syncSession(aliceSession2)
+
+        Log.v("TEST", "=======> AliceSession 2 is ${aliceSession2.sessionParams.deviceId}")
 
         val roomSecondSessionPOV = aliceSession2.getRoom(roomId)
 
@@ -107,7 +100,10 @@ class KeyShareTests : InstrumentedTest {
         }
 
         val outgoingRequestsBefore = aliceSession2.cryptoService().getOutgoingRoomKeyRequests()
+        assertEquals("There should be no request as it's disabled", 0, outgoingRequestsBefore.size)
+
         // Try to request
+        aliceSession2.cryptoService().enableKeyGossiping(true)
         aliceSession2.cryptoService().requestRoomKeyForEvent(receivedEvent.root)
 
         val eventMegolmSessionId = receivedEvent.root.content.toModel<EncryptedEventContent>()?.sessionId
@@ -117,10 +113,6 @@ class KeyShareTests : InstrumentedTest {
         commonTestHelper.waitWithLatch { latch ->
             commonTestHelper.retryPeriodicallyWithLatch(latch) {
                 aliceSession2.cryptoService().getOutgoingRoomKeyRequests()
-                        .filter { req ->
-                            // filter out request that was known before
-                            !outgoingRequestsBefore.any { req.requestId == it.requestId }
-                        }
                         .let {
                             val outgoing = it.firstOrNull { it.sessionId == eventMegolmSessionId }
                             outGoingRequestId = outgoing?.requestId
@@ -141,17 +133,34 @@ class KeyShareTests : InstrumentedTest {
         commonTestHelper.waitWithLatch { latch ->
             commonTestHelper.retryPeriodicallyWithLatch(latch) {
                 // DEBUG LOGS
-                aliceSession.cryptoService().getIncomingRoomKeyRequests().let {
-                    Log.v("TEST", "Incoming request Session 1 (looking for $outGoingRequestId)")
+//                aliceSession.cryptoService().getIncomingRoomKeyRequests().let {
+//                    Log.v("TEST", "Incoming request Session 1 (looking for $outGoingRequestId)")
+//                    Log.v("TEST", "=========================")
+//                    it.forEach { keyRequest ->
+//                        Log.v("TEST", "[ts${keyRequest.localCreationTimestamp}] requestId ${keyRequest.requestId}, for sessionId ${keyRequest.requestBody?.sessionId}")
+//                    }
+//                    Log.v("TEST", "=========================")
+//                }
+
+                val incoming = aliceSession.cryptoService().getIncomingRoomKeyRequests().firstOrNull { it.requestId == outGoingRequestId }
+                incoming != null
+            }
+        }
+
+        commonTestHelper.waitWithLatch { latch ->
+            commonTestHelper.retryPeriodicallyWithLatch(latch) {
+                // DEBUG LOGS
+                aliceSession2.cryptoService().getOutgoingRoomKeyRequests().forEach { keyRequest ->
                     Log.v("TEST", "=========================")
-                    it.forEach { keyRequest ->
-                        Log.v("TEST", "[ts${keyRequest.localCreationTimestamp}] requestId ${keyRequest.requestId}, for sessionId ${keyRequest.requestBody?.sessionId} is ${keyRequest.state}")
-                    }
+                    Log.v("TEST", "requestId ${keyRequest.requestId}, for sessionId ${keyRequest.requestBody?.sessionId}")
+                    Log.v("TEST", "replies -> ${keyRequest.results.joinToString { it.toString() }}")
                     Log.v("TEST", "=========================")
                 }
 
-                val incoming = aliceSession.cryptoService().getIncomingRoomKeyRequests().firstOrNull { it.requestId == outGoingRequestId }
-                incoming?.state == GossipingRequestState.REJECTED
+                val outgoing = aliceSession2.cryptoService().getOutgoingRoomKeyRequests().firstOrNull { it.requestId == outGoingRequestId }
+                val reply = outgoing?.results?.firstOrNull { it.userId == aliceSession.myUserId && it.fromDevice == aliceSession.sessionParams.deviceId }
+                val resultCode = (reply?.result as? RequestResult.Failure)?.code
+                resultCode == WithHeldCode.UNVERIFIED
             }
         }
 
@@ -164,255 +173,309 @@ class KeyShareTests : InstrumentedTest {
         }
 
         // Mark the device as trusted
-        aliceSession.cryptoService().setDeviceVerification(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true), aliceSession.myUserId,
-                aliceSession2.sessionParams.deviceId ?: "")
+        aliceSession.cryptoService().setDeviceVerification(
+                DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true), aliceSession.myUserId,
+                aliceSession2.sessionParams.deviceId ?: ""
+        )
 
         // Re request
         aliceSession2.cryptoService().reRequestRoomKeyForEvent(receivedEvent.root)
 
+        cryptoTestHelper.ensureCanDecrypt(listOf(receivedEvent.eventId), aliceSession2, roomId, listOf(sentEventText ?: ""))
+
+        commonTestHelper.signOutAndClose(aliceSession)
+        commonTestHelper.signOutAndClose(aliceSession2)
+    }
+
+    // See E2ESanityTest for a test regarding secret sharing
+
+    /**
+     * Test that the sender of a message accepts to re-share to another user
+     * if the key was originally shared with him
+     */
+    @Test
+    fun test_reShareIfWasIntendedToBeShared() {
+        val commonTestHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+
+        val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
+        val aliceSession = testData.firstSession
+        val roomFromAlice = aliceSession.getRoom(testData.roomId)!!
+        val bobSession = testData.secondSession!!
+
+        val sentEvent = commonTestHelper.sendTextMessage(roomFromAlice, "Hello", 1).first()
+        val sentEventMegolmSession = sentEvent.root.content.toModel<EncryptedEventContent>()!!.sessionId!!
+
+        // bob should be able to decrypt
+        cryptoTestHelper.ensureCanDecrypt(listOf(sentEvent.eventId), bobSession, testData.roomId, listOf(sentEvent.getLastMessageContent()?.body ?: ""))
+
+        // Let's try to request any how.
+        // As it was share previously alice should accept to reshare
+        bobSession.cryptoService().reRequestRoomKeyForEvent(sentEvent.root)
+
         commonTestHelper.waitWithLatch { latch ->
             commonTestHelper.retryPeriodicallyWithLatch(latch) {
-                aliceSession.cryptoService().getIncomingRoomKeyRequests().let {
-                    Log.v("TEST", "Incoming request Session 1")
-                    Log.v("TEST", "=========================")
-                    it.forEach {
-                        Log.v("TEST", "requestId ${it.requestId}, for sessionId ${it.requestBody?.sessionId} is ${it.state}")
-                    }
-                    Log.v("TEST", "=========================")
-
-                    it.any { it.requestBody?.sessionId == eventMegolmSessionId && it.state == GossipingRequestState.ACCEPTED }
-                }
+                val outgoing = bobSession.cryptoService().getOutgoingRoomKeyRequests().firstOrNull { it.sessionId == sentEventMegolmSession }
+                val aliceReply = outgoing?.results?.firstOrNull { it.userId == aliceSession.myUserId && it.fromDevice == aliceSession.sessionParams.deviceId }
+                aliceReply != null && aliceReply.result is RequestResult.Success
             }
         }
+    }
 
-        Thread.sleep(6_000)
+    /**
+     * Test that our own devices accept to reshare to unverified device if it was shared initialy
+     * if the key was originally shared with him
+     */
+    @Test
+    fun test_reShareToUnverifiedIfWasIntendedToBeShared() {
+        val commonTestHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+
+        val testData = cryptoTestHelper.doE2ETestWithAliceInARoom(true)
+        val aliceSession = testData.firstSession
+        val roomFromAlice = aliceSession.getRoom(testData.roomId)!!
+
+        val aliceNewSession = commonTestHelper.logIntoAccount(aliceSession.myUserId, SessionTestParams(true))
+
+        // we wait for alice first session to be aware of that session?
         commonTestHelper.waitWithLatch { latch ->
             commonTestHelper.retryPeriodicallyWithLatch(latch) {
-                aliceSession2.cryptoService().getOutgoingRoomKeyRequests().let {
-                    it.any { it.requestBody?.sessionId == eventMegolmSessionId && it.state == OutgoingGossipingRequestState.CANCELLED }
-                }
+                val newSession = aliceSession.cryptoService().getUserDevices(aliceSession.myUserId)
+                        .firstOrNull { it.deviceId == aliceNewSession.sessionParams.deviceId }
+                newSession != null
             }
         }
+        val sentEvent = commonTestHelper.sendTextMessage(roomFromAlice, "Hello", 1).first()
+        val sentEventMegolmSession = sentEvent.root.content.toModel<EncryptedEventContent>()!!.sessionId!!
 
-        try {
-            commonTestHelper.runBlockingTest {
-                aliceSession2.cryptoService().decryptEvent(receivedEvent.root, "foo")
+        // Let's try to request any how.
+        // As it was share previously alice should accept to reshare
+        aliceNewSession.cryptoService().reRequestRoomKeyForEvent(sentEvent.root)
+
+        commonTestHelper.waitWithLatch { latch ->
+            commonTestHelper.retryPeriodicallyWithLatch(latch) {
+                val outgoing = aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().firstOrNull { it.sessionId == sentEventMegolmSession }
+                val ownDeviceReply =
+                        outgoing?.results?.firstOrNull { it.userId == aliceSession.myUserId && it.fromDevice == aliceSession.sessionParams.deviceId }
+                ownDeviceReply != null && ownDeviceReply.result is RequestResult.Success
             }
-        } catch (failure: Throwable) {
-            fail("should have been able to decrypt")
         }
-
-        commonTestHelper.signOutAndClose(aliceSession)
-        commonTestHelper.signOutAndClose(aliceSession2)
     }
 
+    /**
+     * Tests that keys reshared with own verified session are done from the earliest known index
+     */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
-    fun test_ShareSSSSSecret() {
-        val aliceSession1 = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
-
-        commonTestHelper.doSync<Unit> {
-            aliceSession1.cryptoService().crossSigningService()
-                    .initializeCrossSigning(
-                            object : UserInteractiveAuthInterceptor {
-                                override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
-                                    promise.resume(
-                                            UserPasswordAuth(
-                                                    user = aliceSession1.myUserId,
-                                                    password = TestConstants.PASSWORD
-                                            )
-                                    )
-                                }
-                            }, it)
-        }
+    fun test_reShareFromTheEarliestKnownIndexWithOwnVerifiedSession() {
+        val commonTestHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
 
-        // Also bootstrap keybackup on first session
-        val creationInfo = commonTestHelper.doSync<MegolmBackupCreationInfo> {
-            aliceSession1.cryptoService().keysBackupService().prepareKeysBackupVersion(null, null, it)
-        }
-        val version = commonTestHelper.doSync<KeysVersion> {
-            aliceSession1.cryptoService().keysBackupService().createKeysBackupVersion(creationInfo, it)
-        }
-        // Save it for gossiping
-        aliceSession1.cryptoService().keysBackupService().saveBackupRecoveryKey(creationInfo.recoveryKey, version = version.version)
+        val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
+        val aliceSession = testData.firstSession
+        val bobSession = testData.secondSession!!
+        val roomFromBob = bobSession.getRoom(testData.roomId)!!
 
-        val aliceSession2 = commonTestHelper.logIntoAccount(aliceSession1.myUserId, SessionTestParams(true))
+        val sentEvents = commonTestHelper.sendTextMessage(roomFromBob, "Hello", 3)
+        val sentEventMegolmSession = sentEvents.first().root.content.toModel<EncryptedEventContent>()!!.sessionId!!
 
-        val aliceVerificationService1 = aliceSession1.cryptoService().verificationService()
-        val aliceVerificationService2 = aliceSession2.cryptoService().verificationService()
+        // Let alice now add a new session
+        val aliceNewSession = commonTestHelper.logIntoAccount(aliceSession.myUserId, SessionTestParams(false))
+        aliceNewSession.cryptoService().enableKeyGossiping(false)
+        commonTestHelper.syncSession(aliceNewSession)
 
-        // force keys download
-        commonTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
-            aliceSession1.cryptoService().downloadKeys(listOf(aliceSession1.myUserId), true, it)
+        // we wait bob first session to be aware of that session?
+        commonTestHelper.waitWithLatch { latch ->
+            commonTestHelper.retryPeriodicallyWithLatch(latch) {
+                val newSession = bobSession.cryptoService().getUserDevices(aliceSession.myUserId)
+                        .firstOrNull { it.deviceId == aliceNewSession.sessionParams.deviceId }
+                newSession != null
+            }
         }
-        commonTestHelper.doSync<MXUsersDevicesMap<CryptoDeviceInfo>> {
-            aliceSession2.cryptoService().downloadKeys(listOf(aliceSession2.myUserId), true, it)
+
+        val newEvent = commonTestHelper.sendTextMessage(roomFromBob, "The New", 1).first()
+        val newEventId = newEvent.eventId
+        val newEventText = newEvent.getLastMessageContent()!!.body
+
+        // alice should be able to decrypt the new one
+        cryptoTestHelper.ensureCanDecrypt(listOf(newEventId), aliceNewSession, testData.roomId, listOf(newEventText))
+        // but not the first one!
+        cryptoTestHelper.ensureCannotDecrypt(sentEvents.map { it.eventId }, aliceNewSession, testData.roomId)
+
+        // All should be using the same session id
+        sentEvents.forEach {
+            assertEquals(sentEventMegolmSession, it.root.content.toModel<EncryptedEventContent>()!!.sessionId)
         }
+        assertEquals(sentEventMegolmSession, newEvent.root.content.toModel<EncryptedEventContent>()!!.sessionId)
 
-        var session1ShortCode: String? = null
-        var session2ShortCode: String? = null
+        // Request a first time, bob should reply with unauthorized and alice should reply with unverified
+        aliceNewSession.cryptoService().enableKeyGossiping(true)
+        aliceNewSession.cryptoService().reRequestRoomKeyForEvent(newEvent.root)
 
-        aliceVerificationService1.addListener(object : VerificationService.Listener {
-            override fun transactionUpdated(tx: VerificationTransaction) {
-                Log.d("#TEST", "AA: tx incoming?:${tx.isIncoming} state ${tx.state}")
-                if (tx is SasVerificationTransaction) {
-                    if (tx.state == VerificationTxState.OnStarted) {
-                        (tx as IncomingSasVerificationTransaction).performAccept()
-                    }
-                    if (tx.state == VerificationTxState.ShortCodeReady) {
-                        session1ShortCode = tx.getDecimalCodeRepresentation()
-                        Thread.sleep(500)
-                        tx.userHasVerifiedShortCode()
-                    }
-                }
-            }
-        })
-
-        aliceVerificationService2.addListener(object : VerificationService.Listener {
-            override fun transactionUpdated(tx: VerificationTransaction) {
-                Log.d("#TEST", "BB: tx incoming?:${tx.isIncoming} state ${tx.state}")
-                if (tx is SasVerificationTransaction) {
-                    if (tx.state == VerificationTxState.ShortCodeReady) {
-                        session2ShortCode = tx.getDecimalCodeRepresentation()
-                        Thread.sleep(500)
-                        tx.userHasVerifiedShortCode()
-                    }
-                }
+        commonTestHelper.waitWithLatch { latch ->
+            commonTestHelper.retryPeriodicallyWithLatch(latch) {
+                val outgoing = aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().firstOrNull { it.sessionId == sentEventMegolmSession }
+                val ownDeviceReply = outgoing?.results
+                        ?.firstOrNull { it.userId == aliceSession.myUserId && it.fromDevice == aliceSession.sessionParams.deviceId }
+                val result = ownDeviceReply?.result
+                Log.v("TEST", "own device result is $result")
+                result != null && result is RequestResult.Failure && result.code == WithHeldCode.UNVERIFIED
             }
-        })
-
-        val txId = "m.testVerif12"
-        aliceVerificationService2.beginKeyVerification(VerificationMethod.SAS, aliceSession1.myUserId, aliceSession1.sessionParams.deviceId
-                ?: "", txId)
+        }
 
         commonTestHelper.waitWithLatch { latch ->
             commonTestHelper.retryPeriodicallyWithLatch(latch) {
-                aliceSession1.cryptoService().getDeviceInfo(aliceSession1.myUserId, aliceSession2.sessionParams.deviceId ?: "")?.isVerified == true
+                val outgoing = aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().firstOrNull { it.sessionId == sentEventMegolmSession }
+                val bobDeviceReply = outgoing?.results
+                        ?.firstOrNull { it.userId == bobSession.myUserId && it.fromDevice == bobSession.sessionParams.deviceId }
+                val result = bobDeviceReply?.result
+                Log.v("TEST", "bob device result is $result")
+                result != null && result is RequestResult.Success && result.chainIndex > 0
             }
         }
 
-        assertNotNull(session1ShortCode)
-        Log.d("#TEST", "session1ShortCode: $session1ShortCode")
-        assertNotNull(session2ShortCode)
-        Log.d("#TEST", "session2ShortCode: $session2ShortCode")
-        assertEquals(session1ShortCode, session2ShortCode)
+        // it's a success but still can't decrypt first message
+        cryptoTestHelper.ensureCannotDecrypt(sentEvents.map { it.eventId }, aliceNewSession, testData.roomId)
 
-        // SSK and USK private keys should have been shared
+        // Mark the new session as verified
+        aliceSession.cryptoService()
+                .verificationService()
+                .markedLocallyAsManuallyVerified(aliceNewSession.myUserId, aliceNewSession.sessionParams.deviceId!!)
 
-        commonTestHelper.waitWithLatch(60_000) { latch ->
+        // Let's now try to request
+        aliceNewSession.cryptoService().reRequestRoomKeyForEvent(sentEvents.first().root)
+
+        commonTestHelper.waitWithLatch { latch ->
             commonTestHelper.retryPeriodicallyWithLatch(latch) {
-                Log.d("#TEST", "CAN XS :${aliceSession2.cryptoService().crossSigningService().getMyCrossSigningKeys()}")
-                aliceSession2.cryptoService().crossSigningService().canCrossSign()
+                // DEBUG LOGS
+                aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().forEach { keyRequest ->
+                    Log.v("TEST", "=========================")
+                    Log.v("TEST", "requestId ${keyRequest.requestId}, for sessionId ${keyRequest.requestBody?.sessionId}")
+                    Log.v("TEST", "replies -> ${keyRequest.results.joinToString { it.toString() }}")
+                    Log.v("TEST", "=========================")
+                }
+                val outgoing = aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().firstOrNull { it.sessionId == sentEventMegolmSession }
+                val ownDeviceReply =
+                        outgoing?.results?.firstOrNull { it.userId == aliceSession.myUserId && it.fromDevice == aliceSession.sessionParams.deviceId }
+                val result = ownDeviceReply?.result
+                result != null && result is RequestResult.Success && result.chainIndex == 0
             }
         }
 
-        // Test that key backup key has been shared to
-        commonTestHelper.waitWithLatch(60_000) { latch ->
-            val keysBackupService = aliceSession2.cryptoService().keysBackupService()
+        // now the new session should be able to decrypt all!
+        cryptoTestHelper.ensureCanDecrypt(
+                sentEvents.map { it.eventId },
+                aliceNewSession,
+                testData.roomId,
+                sentEvents.map { it.getLastMessageContent()!!.body }
+        )
+
+        // Additional test, can we check that bob replied successfully but with a ratcheted key
+        commonTestHelper.waitWithLatch { latch ->
             commonTestHelper.retryPeriodicallyWithLatch(latch) {
-                Log.d("#TEST", "Recovery :${keysBackupService.getKeyBackupRecoveryKeyInfo()?.recoveryKey}")
-                keysBackupService.getKeyBackupRecoveryKeyInfo()?.recoveryKey == creationInfo.recoveryKey
+                val outgoing = aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().firstOrNull { it.sessionId == sentEventMegolmSession }
+                val bobReply = outgoing?.results?.firstOrNull { it.userId == bobSession.myUserId }
+                val result = bobReply?.result
+                result != null && result is RequestResult.Success && result.chainIndex == 3
             }
         }
 
-        commonTestHelper.signOutAndClose(aliceSession1)
-        commonTestHelper.signOutAndClose(aliceSession2)
+        commonTestHelper.signOutAndClose(aliceNewSession)
+        commonTestHelper.signOutAndClose(aliceSession)
+        commonTestHelper.signOutAndClose(bobSession)
     }
 
+    /**
+     * Tests that we don't cancel a request to early on first forward if the index is not good enough
+     */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
-    fun test_ImproperKeyShareBug() {
-        val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
+    fun test_dontCancelToEarly() {
+        val commonTestHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
 
-        commonTestHelper.doSync<Unit> {
-            aliceSession.cryptoService().crossSigningService()
-                    .initializeCrossSigning(
-                            object : UserInteractiveAuthInterceptor {
-                                override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
-                                    promise.resume(
-                                            UserPasswordAuth(
-                                                    user = aliceSession.myUserId,
-                                                    password = TestConstants.PASSWORD,
-                                                    session = flowResponse.session
-                                            )
-                                    )
-                                }
-                            }, it)
-        }
+        val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
+        val aliceSession = testData.firstSession
+        val bobSession = testData.secondSession!!
+        val roomFromBob = bobSession.getRoom(testData.roomId)!!
 
-        // Create an encrypted room and send a couple of messages
-        val roomId = commonTestHelper.runBlockingTest {
-            aliceSession.roomService().createRoom(
-                    CreateRoomParams().apply {
-                        visibility = RoomDirectoryVisibility.PRIVATE
-                        enableEncryption()
-                    }
-            )
-        }
-        val roomAlicePov = aliceSession.getRoom(roomId)
-        assertNotNull(roomAlicePov)
-        Thread.sleep(1_000)
-        assertTrue(roomAlicePov?.roomCryptoService()?.isEncrypted() == true)
-        val secondEventId = commonTestHelper.sendTextMessage(roomAlicePov!!, "Message", 3)[1].eventId
-
-        // Create bob session
-
-        val bobSession = commonTestHelper.createAccount(TestConstants.USER_BOB, SessionTestParams(true))
-        commonTestHelper.doSync<Unit> {
-            bobSession.cryptoService().crossSigningService()
-                    .initializeCrossSigning(
-                            object : UserInteractiveAuthInterceptor {
-                                override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation<UIABaseAuth>) {
-                                    promise.resume(
-                                            UserPasswordAuth(
-                                                    user = bobSession.myUserId,
-                                                    password = TestConstants.PASSWORD,
-                                                    session = flowResponse.session
-                                            )
-                                    )
-                                }
-                            }, it)
-        }
+        val sentEvents = commonTestHelper.sendTextMessage(roomFromBob, "Hello", 3)
+        val sentEventMegolmSession = sentEvents.first().root.content.toModel<EncryptedEventContent>()!!.sessionId!!
 
-        // Let alice invite bob
-        commonTestHelper.runBlockingTest {
-            roomAlicePov.membershipService().invite(bobSession.myUserId, null)
+        // Let alice now add a new session
+        val aliceNewSession = commonTestHelper.logIntoAccount(aliceSession.myUserId, SessionTestParams(true))
+
+        // we wait bob first session to be aware of that session?
+        commonTestHelper.waitWithLatch { latch ->
+            commonTestHelper.retryPeriodicallyWithLatch(latch) {
+                val newSession = bobSession.cryptoService().getUserDevices(aliceSession.myUserId)
+                        .firstOrNull { it.deviceId == aliceNewSession.sessionParams.deviceId }
+                newSession != null
+            }
         }
 
-        commonTestHelper.runBlockingTest {
-            bobSession.roomService().joinRoom(roomAlicePov.roomId, null, emptyList())
+        val newEvent = commonTestHelper.sendTextMessage(roomFromBob, "The New", 1).first()
+        val newEventId = newEvent.eventId
+        val newEventText = newEvent.getLastMessageContent()!!.body
+
+        // alice should be able to decrypt the new one
+        cryptoTestHelper.ensureCanDecrypt(listOf(newEventId), aliceNewSession, testData.roomId, listOf(newEventText))
+        // but not the first one!
+        cryptoTestHelper.ensureCannotDecrypt(sentEvents.map { it.eventId }, aliceNewSession, testData.roomId)
+
+        // All should be using the same session id
+        sentEvents.forEach {
+            assertEquals(sentEventMegolmSession, it.root.content.toModel<EncryptedEventContent>()!!.sessionId)
         }
+        assertEquals(sentEventMegolmSession, newEvent.root.content.toModel<EncryptedEventContent>()!!.sessionId)
 
-        // we want to discard alice outbound session
-        aliceSession.cryptoService().discardOutboundSession(roomAlicePov.roomId)
+        // Mark the new session as verified
+        aliceSession.cryptoService()
+                .verificationService()
+                .markedLocallyAsManuallyVerified(aliceNewSession.myUserId, aliceNewSession.sessionParams.deviceId!!)
 
-        // and now resend a new message to reset index to 0
-        commonTestHelper.sendTextMessage(roomAlicePov, "After", 1)
+        // /!\ Stop initial alice session syncing so that it can't reply
+        aliceSession.cryptoService().enableKeyGossiping(false)
+        aliceSession.stopSync()
 
-        val roomRoomBobPov = aliceSession.getRoom(roomId)
-        val beforeJoin = roomRoomBobPov!!.getTimelineEvent(secondEventId)
+        // Let's now try to request
+        aliceNewSession.cryptoService().reRequestRoomKeyForEvent(sentEvents.first().root)
 
-        var dRes = tryOrNull {
-            commonTestHelper.runBlockingTest {
-                bobSession.cryptoService().decryptEvent(beforeJoin!!.root, "")
+        // Should get a reply from bob and not from alice
+        commonTestHelper.waitWithLatch { latch ->
+            commonTestHelper.retryPeriodicallyWithLatch(latch) {
+              //  Log.d("#TEST", "outgoing key requests :${aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().joinToString { it.sessionId ?: "?" }}")
+                val outgoing = aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().firstOrNull { it.sessionId == sentEventMegolmSession }
+                val bobReply = outgoing?.results?.firstOrNull { it.userId == bobSession.myUserId }
+                val result = bobReply?.result
+                result != null && result is RequestResult.Success && result.chainIndex == 3
             }
         }
 
-        assert(dRes == null)
-
-        // Try to re-ask the keys
+        val outgoingReq = aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().firstOrNull { it.sessionId == sentEventMegolmSession }
 
-        bobSession.cryptoService().reRequestRoomKeyForEvent(beforeJoin!!.root)
+        assertNull("We should not have a reply from first session", outgoingReq!!.results.firstOrNull { it.fromDevice == aliceSession.sessionParams.deviceId })
+        assertEquals("The request should not be canceled", OutgoingRoomKeyRequestState.SENT, outgoingReq.state)
 
-        Thread.sleep(3_000)
+        // let's wake up alice
+        aliceSession.cryptoService().enableKeyGossiping(true)
+        aliceSession.startSync(true)
 
-        // With the bug the first session would have improperly reshare that key :/
-        dRes = tryOrNull {
-            commonTestHelper.runBlockingTest {
-                bobSession.cryptoService().decryptEvent(beforeJoin.root, "")
+        // We should now get a reply from first session
+        commonTestHelper.waitWithLatch { latch ->
+            commonTestHelper.retryPeriodicallyWithLatch(latch) {
+                val outgoing = aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().firstOrNull { it.sessionId == sentEventMegolmSession }
+                val ownDeviceReply =
+                        outgoing?.results?.firstOrNull { it.userId == aliceSession.myUserId && it.fromDevice == aliceSession.sessionParams.deviceId }
+                val result = ownDeviceReply?.result
+                result != null && result is RequestResult.Success && result.chainIndex == 0
             }
         }
-        Log.d("#TEST", "KS: sgould not decrypt that ${beforeJoin.root.getClearContent().toModel<MessageContent>()?.body}")
-        assert(dRes?.clearEvent == null)
+
+        // It should be in sent then cancel
+        val outgoing = aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().firstOrNull { it.sessionId == sentEventMegolmSession }
+        assertEquals("The request should be canceled", OutgoingRoomKeyRequestState.SENT_THEN_CANCELED, outgoing!!.state)
+
+        commonTestHelper.signOutAndClose(aliceNewSession)
+        commonTestHelper.signOutAndClose(aliceSession)
+        commonTestHelper.signOutAndClose(bobSession)
     }
 }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt
index bad9fd0f68775a6618767cff21546cf059e96f73..cb31a2232fb672c7e54fecbfff1a5c5c91e90d9e 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt
@@ -21,7 +21,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import org.junit.Assert
 import org.junit.FixMethodOrder
-import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -29,6 +28,7 @@ import org.matrix.android.sdk.InstrumentedTest
 import org.matrix.android.sdk.api.NoOpMatrixCallback
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.session.crypto.MXCryptoError
+import org.matrix.android.sdk.api.session.crypto.RequestResult
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
 import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
@@ -46,12 +46,11 @@ import org.matrix.android.sdk.common.TestConstants
 @LargeTest
 class WithHeldTests : InstrumentedTest {
 
-    private val testHelper = CommonTestHelper(context())
-    private val cryptoTestHelper = CryptoTestHelper(testHelper)
-
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun test_WithHeldUnverifiedReason() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+
         // =============================
         // ARRANGE
         // =============================
@@ -69,7 +68,6 @@ class WithHeldTests : InstrumentedTest {
         val roomAlicePOV = aliceSession.getRoom(roomId)!!
 
         val bobUnverifiedSession = testHelper.logIntoAccount(bobSession.myUserId, SessionTestParams(true))
-
         // =============================
         // ACT
         // =============================
@@ -88,6 +86,7 @@ class WithHeldTests : InstrumentedTest {
 
         val eventBobPOV = bobUnverifiedSession.getRoom(roomId)?.getTimelineEvent(timelineEvent.eventId)!!
 
+        val megolmSessionId = eventBobPOV.root.content.toModel<EncryptedEventContent>()!!.sessionId!!
         // =============================
         // ASSERT
         // =============================
@@ -103,9 +102,23 @@ class WithHeldTests : InstrumentedTest {
             val type = (failure as MXCryptoError.Base).errorType
             val technicalMessage = failure.technicalMessage
             Assert.assertEquals("Error should be withheld", MXCryptoError.ErrorType.KEYS_WITHHELD, type)
-            Assert.assertEquals("Cause should be unverified", WithHeldCode.UNVERIFIED.value, technicalMessage)
+            Assert.assertEquals("Cause should be unverified", WithHeldCode.UNAUTHORISED.value, technicalMessage)
         }
 
+        // Let's see if the reply we got from bob first session is unverified
+        testHelper.waitWithLatch { latch ->
+            testHelper.retryPeriodicallyWithLatch(latch) {
+                bobUnverifiedSession.cryptoService().getOutgoingRoomKeyRequests()
+                        .firstOrNull { it.sessionId == megolmSessionId }
+                        ?.results
+                        ?.firstOrNull { it.fromDevice == bobSession.sessionParams.deviceId }
+                        ?.result
+                        ?.let {
+                            it as? RequestResult.Failure
+                        }
+                        ?.code == WithHeldCode.UNVERIFIED
+            }
+        }
         // enable back sending to unverified
         aliceSession.cryptoService().setGlobalBlacklistUnverifiedDevices(false)
 
@@ -130,7 +143,7 @@ class WithHeldTests : InstrumentedTest {
             val type = (failure as MXCryptoError.Base).errorType
             val technicalMessage = failure.technicalMessage
             Assert.assertEquals("Error should be withheld", MXCryptoError.ErrorType.KEYS_WITHHELD, type)
-            Assert.assertEquals("Cause should be unverified", WithHeldCode.UNVERIFIED.value, technicalMessage)
+            Assert.assertEquals("Cause should be unverified", WithHeldCode.UNAUTHORISED.value, technicalMessage)
         }
 
         testHelper.signOutAndClose(aliceSession)
@@ -139,21 +152,25 @@ class WithHeldTests : InstrumentedTest {
     }
 
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun test_WithHeldNoOlm() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+
         val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
         val aliceSession = testData.firstSession
         val bobSession = testData.secondSession!!
         val aliceInterceptor = testHelper.getTestInterceptor(aliceSession)
 
         // Simulate no OTK
-        aliceInterceptor!!.addRule(MockOkHttpInterceptor.SimpleRule(
-                "/keys/claim",
-                200,
-                """
+        aliceInterceptor!!.addRule(
+                MockOkHttpInterceptor.SimpleRule(
+                        "/keys/claim",
+                        200,
+                        """
                    { "one_time_keys" : {} } 
                 """
-        ))
+                )
+        )
         Log.d("#TEST", "Recovery :${aliceSession.sessionParams.credentials.accessToken}")
 
         val roomAlicePov = aliceSession.getRoom(testData.roomId)!!
@@ -184,7 +201,10 @@ class WithHeldTests : InstrumentedTest {
 
         // Ensure that alice has marked the session to be shared with bob
         val sessionId = eventBobPOV!!.root.content.toModel<EncryptedEventContent>()!!.sessionId!!
-        val chainIndex = aliceSession.cryptoService().getSharedWithInfo(testData.roomId, sessionId).getObject(bobSession.myUserId, bobSession.sessionParams.credentials.deviceId)
+        val chainIndex = aliceSession.cryptoService().getSharedWithInfo(testData.roomId, sessionId).getObject(
+                bobSession.myUserId,
+                bobSession.sessionParams.credentials.deviceId
+        )
 
         Assert.assertEquals("Alice should have marked bob's device for this session", 0, chainIndex)
         // Add a new device for bob
@@ -202,7 +222,10 @@ class WithHeldTests : InstrumentedTest {
             }
         }
 
-        val chainIndex2 = aliceSession.cryptoService().getSharedWithInfo(testData.roomId, sessionId).getObject(bobSecondSession.myUserId, bobSecondSession.sessionParams.credentials.deviceId)
+        val chainIndex2 = aliceSession.cryptoService().getSharedWithInfo(testData.roomId, sessionId).getObject(
+                bobSecondSession.myUserId,
+                bobSecondSession.sessionParams.credentials.deviceId
+        )
 
         Assert.assertEquals("Alice should have marked bob's device for this session", 1, chainIndex2)
 
@@ -212,8 +235,10 @@ class WithHeldTests : InstrumentedTest {
     }
 
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun test_WithHeldKeyRequest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+
         val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
         val aliceSession = testData.firstSession
         val bobSession = testData.secondSession!!
@@ -259,5 +284,8 @@ class WithHeldTests : InstrumentedTest {
                 wc?.code == WithHeldCode.UNAUTHORISED
             }
         }
+
+        testHelper.signOutAndClose(aliceSession)
+        testHelper.signOutAndClose(bobSecondSession)
     }
 }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPasswordTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPasswordTest.kt
index d035fe5fdea677c056ffcae700542ef97a5b1b8a..9bf08f6fc043d3760847d967cd5450b04924246d 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPasswordTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPasswordTest.kt
@@ -54,9 +54,11 @@ class KeysBackupPasswordTest : InstrumentedTest {
         assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
 
         // Reverse operation
-        val retrievedPrivateKey = retrievePrivateKeyWithPassword(PASSWORD,
+        val retrievedPrivateKey = retrievePrivateKeyWithPassword(
+                PASSWORD,
                 generatePrivateKeyResult.salt,
-                generatePrivateKeyResult.iterations)
+                generatePrivateKeyResult.iterations
+        )
 
         assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
         assertArrayEquals(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
@@ -102,9 +104,11 @@ class KeysBackupPasswordTest : InstrumentedTest {
         assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
 
         // Reverse operation, with bad password
-        val retrievedPrivateKey = retrievePrivateKeyWithPassword(BAD_PASSWORD,
+        val retrievedPrivateKey = retrievePrivateKeyWithPassword(
+                BAD_PASSWORD,
                 generatePrivateKeyResult.salt,
-                generatePrivateKeyResult.iterations)
+                generatePrivateKeyResult.iterations
+        )
 
         assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
         assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
@@ -122,9 +126,11 @@ class KeysBackupPasswordTest : InstrumentedTest {
         assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
 
         // Reverse operation, with bad iteration
-        val retrievedPrivateKey = retrievePrivateKeyWithPassword(PASSWORD,
+        val retrievedPrivateKey = retrievePrivateKeyWithPassword(
+                PASSWORD,
                 generatePrivateKeyResult.salt,
-                500_001)
+                500_001
+        )
 
         assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
         assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
@@ -142,9 +148,11 @@ class KeysBackupPasswordTest : InstrumentedTest {
         assertEquals(OlmPkDecryption.privateKeyLength(), generatePrivateKeyResult.privateKey.size)
 
         // Reverse operation, with bad iteration
-        val retrievedPrivateKey = retrievePrivateKeyWithPassword(PASSWORD,
+        val retrievedPrivateKey = retrievePrivateKeyWithPassword(
+                PASSWORD,
                 BAD_SALT,
-                generatePrivateKeyResult.iterations)
+                generatePrivateKeyResult.iterations
+        )
 
         assertEquals(OlmPkDecryption.privateKeyLength(), retrievedPrivateKey.size)
         assertByteArrayNotEqual(generatePrivateKeyResult.privateKey, retrievedPrivateKey)
@@ -168,7 +176,8 @@ class KeysBackupPasswordTest : InstrumentedTest {
                 116.toByte(), 224.toByte(), 229.toByte(), 224.toByte(), 9.toByte(), 3.toByte(), 178.toByte(), 162.toByte(),
                 120.toByte(), 23.toByte(), 108.toByte(), 218.toByte(), 22.toByte(), 61.toByte(), 241.toByte(), 200.toByte(),
                 235.toByte(), 173.toByte(), 236.toByte(), 100.toByte(), 115.toByte(), 247.toByte(), 33.toByte(), 132.toByte(),
-                195.toByte(), 154.toByte(), 64.toByte(), 158.toByte(), 184.toByte(), 148.toByte(), 20.toByte(), 85.toByte())
+                195.toByte(), 154.toByte(), 64.toByte(), 158.toByte(), 184.toByte(), 148.toByte(), 20.toByte(), 85.toByte()
+        )
 
         assertArrayEquals(privateKeyBytes, retrievedPrivateKey)
     }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt
index 3220f161fa499a131b968baff01631372cdf11c0..9136272b1ee7fc396c7a162e797efe1c75a5d72d 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt
@@ -24,7 +24,6 @@ import org.junit.Assert.assertNotNull
 import org.junit.Assert.assertNull
 import org.junit.Assert.assertTrue
 import org.junit.FixMethodOrder
-import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -37,7 +36,9 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupLastVersio
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupVersionTrust
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupVersionTrustSignature
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
 import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
 import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
 import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
@@ -54,18 +55,16 @@ import java.util.concurrent.CountDownLatch
 @LargeTest
 class KeysBackupTest : InstrumentedTest {
 
-    private val testHelper = CommonTestHelper(context())
-    private val cryptoTestHelper = CryptoTestHelper(testHelper)
-    private val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
-
     /**
      * - From doE2ETestWithAliceAndBobInARoomWithEncryptedMessages, we should have no backed up keys
      * - Check backup keys after having marked one as backed up
      * - Reset keys backup markers
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun roomKeysTest_testBackupStore_ok() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
 
         // From doE2ETestWithAliceAndBobInARoomWithEncryptedMessages, we should have no backed up keys
@@ -104,6 +103,8 @@ class KeysBackupTest : InstrumentedTest {
      */
     @Test
     fun prepareKeysBackupVersionTest() {
+        val testHelper = CommonTestHelper(context())
+
         val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
 
         assertNotNull(bobSession.cryptoService().keysBackupService())
@@ -132,7 +133,11 @@ class KeysBackupTest : InstrumentedTest {
      */
     @Test
     fun createKeysBackupVersionTest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+
         val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
+        cryptoTestHelper.initializeCrossSigning(bobSession)
 
         val keysBackup = bobSession.cryptoService().keysBackupService()
 
@@ -147,13 +152,46 @@ class KeysBackupTest : InstrumentedTest {
         assertFalse(keysBackup.isEnabled)
 
         // Create the version
-        testHelper.doSync<KeysVersion> {
+        val version = testHelper.doSync<KeysVersion> {
             keysBackup.createKeysBackupVersion(megolmBackupCreationInfo, it)
         }
 
         // Backup must be enable now
         assertTrue(keysBackup.isEnabled)
 
+        // Check that it's signed with MSK
+        val versionResult = testHelper.doSync<KeysVersionResult?> {
+            keysBackup.getVersion(version.version, it)
+        }
+        val trust = testHelper.doSync<KeysBackupVersionTrust> {
+            keysBackup.getKeysBackupTrust(versionResult!!, it)
+        }
+
+        assertEquals("Should have 2 signatures", 2, trust.signatures.size)
+
+        trust.signatures
+                .firstOrNull { it is KeysBackupVersionTrustSignature.DeviceSignature }
+                .let {
+                    assertNotNull("Should be signed by a device", it)
+                    it as KeysBackupVersionTrustSignature.DeviceSignature
+                }.let {
+                    assertEquals("Should be signed by current device", bobSession.sessionParams.deviceId, it.deviceId)
+                    assertTrue("Signature should be valid", it.valid)
+                }
+
+        trust.signatures
+                .firstOrNull { it is KeysBackupVersionTrustSignature.UserSignature }
+                .let {
+                    assertNotNull("Should be signed by a user", it)
+                    it as KeysBackupVersionTrustSignature.UserSignature
+                }.let {
+                    val msk = bobSession.cryptoService().crossSigningService()
+                            .getMyCrossSigningKeys()?.masterKey()?.unpaddedBase64PublicKey
+                    assertEquals("Should be signed by my msk 1", msk, it.keyId)
+                    assertEquals("Should be signed by my msk 2", msk, it.cryptoCrossSigningKey?.unpaddedBase64PublicKey)
+                    assertTrue("Signature should be valid", it.valid)
+                }
+
         stateObserver.stopAndCheckStates(null)
         testHelper.signOutAndClose(bobSession)
     }
@@ -163,8 +201,11 @@ class KeysBackupTest : InstrumentedTest {
      * - Check the backup completes
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun backupAfterCreateKeysBackupVersionTest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
 
         keysBackupTestHelper.waitForKeybackUpBatching()
@@ -204,8 +245,11 @@ class KeysBackupTest : InstrumentedTest {
      * Check that backupAllGroupSessions() returns valid data
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun backupAllGroupSessionsTest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
 
         val keysBackup = cryptoTestData.firstSession.cryptoService().keysBackupService()
@@ -249,8 +293,11 @@ class KeysBackupTest : InstrumentedTest {
      * - Compare the decrypted megolm key with the original one
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun testEncryptAndDecryptKeysBackupData() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
 
         val keysBackup = cryptoTestData.firstSession.cryptoService().keysBackupService() as DefaultKeysBackupService
@@ -272,10 +319,12 @@ class KeysBackupTest : InstrumentedTest {
         assertNotNull(decryption)
         // - Check decryptKeyBackupData() returns stg
         val sessionData = keysBackup
-                .decryptKeyBackupData(keyBackupData,
+                .decryptKeyBackupData(
+                        keyBackupData,
                         session.olmInboundGroupSession!!.sessionIdentifier(),
                         cryptoTestData.roomId,
-                        decryption!!)
+                        decryption!!
+                )
         assertNotNull(sessionData)
         // - Compare the decrypted megolm key with the original one
         keysBackupTestHelper.assertKeysEquals(session.exportKeys(), sessionData)
@@ -291,13 +340,17 @@ class KeysBackupTest : InstrumentedTest {
      * - Restore must be successful
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun restoreKeysBackupTest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
 
         // - Restore the e2e backup from the homeserver
         val importRoomKeysResult = testHelper.doSync<ImportRoomKeysResult> {
-            testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
+            testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(
+                    testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
                     testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
                     null,
                     null,
@@ -375,8 +428,11 @@ class KeysBackupTest : InstrumentedTest {
      * - It must be trusted and must have with 2 signatures now
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun trustKeyBackupVersionTest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         // - Do an e2e backup to the homeserver with a recovery key
         // - And log Alice on a new device
         val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
@@ -435,8 +491,11 @@ class KeysBackupTest : InstrumentedTest {
      * - It must be trusted and must have with 2 signatures now
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun trustKeyBackupVersionWithRecoveryKeyTest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         // - Do an e2e backup to the homeserver with a recovery key
         // - And log Alice on a new device
         val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
@@ -493,8 +552,11 @@ class KeysBackupTest : InstrumentedTest {
      * - The backup must still be untrusted and disabled
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun trustKeyBackupVersionWithWrongRecoveryKeyTest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         // - Do an e2e backup to the homeserver with a recovery key
         // - And log Alice on a new device
         val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
@@ -535,8 +597,11 @@ class KeysBackupTest : InstrumentedTest {
      * - It must be trusted and must have with 2 signatures now
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun trustKeyBackupVersionWithPasswordTest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         val password = "Password"
 
         // - Do an e2e backup to the homeserver with a password
@@ -595,8 +660,11 @@ class KeysBackupTest : InstrumentedTest {
      * - The backup must still be untrusted and disabled
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun trustKeyBackupVersionWithWrongPasswordTest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         val password = "Password"
         val badPassword = "Bad Password"
 
@@ -636,8 +704,11 @@ class KeysBackupTest : InstrumentedTest {
      * - It must fail
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun restoreKeysBackupWithAWrongRecoveryKeyTest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
 
         // - Try to restore the e2e backup with a wrong recovery key
@@ -670,8 +741,11 @@ class KeysBackupTest : InstrumentedTest {
      * - Restore must be successful
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun testBackupWithPassword() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         val password = "password"
 
         val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
@@ -680,7 +754,8 @@ class KeysBackupTest : InstrumentedTest {
         val steps = ArrayList<StepProgressListener.Step>()
 
         val importRoomKeysResult = testHelper.doSync<ImportRoomKeysResult> {
-            testData.aliceSession2.cryptoService().keysBackupService().restoreKeyBackupWithPassword(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
+            testData.aliceSession2.cryptoService().keysBackupService().restoreKeyBackupWithPassword(
+                    testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
                     password,
                     null,
                     null,
@@ -726,8 +801,11 @@ class KeysBackupTest : InstrumentedTest {
      * - It must fail
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun restoreKeysBackupWithAWrongPasswordTest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         val password = "password"
         val wrongPassword = "passw0rd"
 
@@ -763,15 +841,19 @@ class KeysBackupTest : InstrumentedTest {
      * - Restore must be successful
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun testUseRecoveryKeyToRestoreAPasswordBasedKeysBackup() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         val password = "password"
 
         val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
 
         // - Restore the e2e backup with the recovery key.
         val importRoomKeysResult = testHelper.doSync<ImportRoomKeysResult> {
-            testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
+            testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(
+                    testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
                     testData.prepareKeysBackupDataResult.megolmBackupCreationInfo.recoveryKey,
                     null,
                     null,
@@ -792,8 +874,11 @@ class KeysBackupTest : InstrumentedTest {
      * - It must fail
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun testUsePasswordToRestoreARecoveryKeyBasedKeysBackup() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
 
         // - Try to restore the e2e backup with a password
@@ -824,8 +909,11 @@ class KeysBackupTest : InstrumentedTest {
      * - Check the returned KeysVersionResult is trusted
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun testIsKeysBackupTrusted() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         // - Create a backup version
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
 
@@ -850,7 +938,7 @@ class KeysBackupTest : InstrumentedTest {
         assertTrue(keysBackupVersionTrust.usable)
         assertEquals(1, keysBackupVersionTrust.signatures.size)
 
-        val signature = keysBackupVersionTrust.signatures[0]
+        val signature = keysBackupVersionTrust.signatures[0] as KeysBackupVersionTrustSignature.DeviceSignature
         assertTrue(signature.valid)
         assertNotNull(signature.device)
         assertEquals(cryptoTestData.firstSession.cryptoService().getMyDevice().deviceId, signature.deviceId)
@@ -860,66 +948,6 @@ class KeysBackupTest : InstrumentedTest {
         cryptoTestData.cleanUp(testHelper)
     }
 
-    /**
-     * Check backup starts automatically if there is an existing and compatible backup
-     * version on the homeserver.
-     * - Create a backup version
-     * - Restart alice session
-     * -> The new alice session must back up to the same version
-     */
-    @Test
-    @Ignore("This test will be ignored until it is fixed")
-    fun testCheckAndStartKeysBackupWhenRestartingAMatrixSession() {
-        // - Create a backup version
-        val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
-
-        val keysBackup = cryptoTestData.firstSession.cryptoService().keysBackupService()
-
-        val stateObserver = StateObserver(keysBackup)
-
-        assertFalse(keysBackup.isEnabled)
-
-        val keyBackupCreationInfo = keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
-
-        assertTrue(keysBackup.isEnabled)
-
-        // - Restart alice session
-        // - Log Alice on a new device
-        val aliceSession2 = testHelper.logIntoAccount(cryptoTestData.firstSession.myUserId, KeysBackupTestConstants.defaultSessionParamsWithInitialSync)
-
-        cryptoTestData.cleanUp(testHelper)
-
-        val keysBackup2 = aliceSession2.cryptoService().keysBackupService()
-
-        val stateObserver2 = StateObserver(keysBackup2)
-
-        // -> The new alice session must back up to the same version
-        val latch = CountDownLatch(1)
-        var count = 0
-        keysBackup2.addListener(object : KeysBackupStateListener {
-            override fun onStateChange(newState: KeysBackupState) {
-                // Check the backup completes
-                if (newState == KeysBackupState.ReadyToBackUp) {
-                    count++
-
-                    if (count == 2) {
-                        // Remove itself from the list of listeners
-                        keysBackup2.removeListener(this)
-
-                        latch.countDown()
-                    }
-                }
-            }
-        })
-        testHelper.await(latch)
-
-        assertEquals(keyBackupCreationInfo.version, keysBackup2.currentBackupVersion)
-
-        stateObserver.stopAndCheckStates(null)
-        stateObserver2.stopAndCheckStates(null)
-        testHelper.signOutAndClose(aliceSession2)
-    }
-
     /**
      * Check WrongBackUpVersion state
      *
@@ -930,6 +958,10 @@ class KeysBackupTest : InstrumentedTest {
      */
     @Test
     fun testBackupWhenAnotherBackupWasCreated() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         // - Create a backup version
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
 
@@ -1000,8 +1032,11 @@ class KeysBackupTest : InstrumentedTest {
      * -> It must success
      */
     @Test
-    @Ignore("This test will be ignored until it is fixed")
     fun testBackupAfterVerifyingADevice() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         // - Create a backup version
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
 
@@ -1034,6 +1069,8 @@ class KeysBackupTest : InstrumentedTest {
         // - Try to backup all in aliceSession2, it must fail
         val keysBackup2 = aliceSession2.cryptoService().keysBackupService()
 
+        assertFalse("Backup should not be enabled", keysBackup2.isEnabled)
+
         val stateObserver2 = StateObserver(keysBackup2)
 
         var isSuccessful = false
@@ -1051,11 +1088,15 @@ class KeysBackupTest : InstrumentedTest {
         assertFalse(isSuccessful)
 
         // Backup state must be NotTrusted
-        assertEquals(KeysBackupState.NotTrusted, keysBackup2.state)
-        assertFalse(keysBackup2.isEnabled)
+        assertEquals("Backup state must be NotTrusted", KeysBackupState.NotTrusted, keysBackup2.state)
+        assertFalse("Backup should not be enabled", keysBackup2.isEnabled)
 
         // - Validate the old device from the new one
-        aliceSession2.cryptoService().setDeviceVerification(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true), aliceSession2.myUserId, oldDeviceId)
+        aliceSession2.cryptoService().setDeviceVerification(
+                DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true),
+                aliceSession2.myUserId,
+                oldDeviceId
+        )
 
         // -> Backup should automatically enable on the new device
         val latch4 = CountDownLatch(1)
@@ -1094,6 +1135,10 @@ class KeysBackupTest : InstrumentedTest {
      */
     @Test
     fun deleteKeysBackupTest() {
+        val testHelper = CommonTestHelper(context())
+        val cryptoTestHelper = CryptoTestHelper(testHelper)
+        val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
+
         // - Create a backup version
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
 
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt
index ac83cb88821dbab69503276b023d547468d41079..2220536e28c7579d8cf5af4367b425e2deb494a4 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt
@@ -88,10 +88,12 @@ internal class KeysBackupTestHelper(
 
         stateObserver.stopAndCheckStates(null)
 
-        return KeysBackupScenarioData(cryptoTestData,
+        return KeysBackupScenarioData(
+                cryptoTestData,
                 aliceKeys,
                 prepareKeysBackupDataResult,
-                aliceSession2)
+                aliceSession2
+        )
     }
 
     fun prepareAndCreateKeysBackupData(keysBackup: KeysBackupService,
@@ -104,14 +106,14 @@ internal class KeysBackupTestHelper(
 
         Assert.assertNotNull(megolmBackupCreationInfo)
 
-        Assert.assertFalse(keysBackup.isEnabled)
+        Assert.assertFalse("Key backup should not be enabled before creation", keysBackup.isEnabled)
 
         // Create the version
         val keysVersion = testHelper.doSync<KeysVersion> {
             keysBackup.createKeysBackupVersion(megolmBackupCreationInfo, it)
         }
 
-        Assert.assertNotNull(keysVersion.version)
+        Assert.assertNotNull("Key backup version should not be null", keysVersion.version)
 
         // Backup must be enable now
         Assert.assertTrue(keysBackup.isEnabled)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt
index a882f690132c3da214982a50d10f8150e7f79675..c758050fc9548f4a1fb926462e7ffb2e6c211279 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt
@@ -207,14 +207,16 @@ class QuadSTests : InstrumentedTest {
 
         // Assert that can decrypt with both keys
         testHelper.runBlockingTest {
-            aliceSession.sharedSecretStorageService().getSecret("my.secret",
+            aliceSession.sharedSecretStorageService().getSecret(
+                    "my.secret",
                     keyId1,
                     RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey)!!
             )
         }
 
         testHelper.runBlockingTest {
-            aliceSession.sharedSecretStorageService().getSecret("my.secret",
+            aliceSession.sharedSecretStorageService().getSecret(
+                    "my.secret",
                     keyId2,
                     RawBytesKeySpec.fromRecoveryKey(key2Info.recoveryKey)!!
             )
@@ -245,13 +247,15 @@ class QuadSTests : InstrumentedTest {
 
         testHelper.runBlockingTest {
             try {
-                aliceSession.sharedSecretStorageService().getSecret("my.secret",
+                aliceSession.sharedSecretStorageService().getSecret(
+                        "my.secret",
                         keyId1,
                         RawBytesKeySpec.fromPassphrase(
                                 "A bad passphrase",
                                 key1Info.content?.passphrase?.salt ?: "",
                                 key1Info.content?.passphrase?.iterations ?: 0,
-                                null)
+                                null
+                        )
                 )
             } catch (throwable: Throwable) {
                 assert(throwable is SharedSecretStorageError.BadMac)
@@ -260,13 +264,15 @@ class QuadSTests : InstrumentedTest {
 
         // Now try with correct key
         testHelper.runBlockingTest {
-            aliceSession.sharedSecretStorageService().getSecret("my.secret",
+            aliceSession.sharedSecretStorageService().getSecret(
+                    "my.secret",
                     keyId1,
                     RawBytesKeySpec.fromPassphrase(
                             passphrase,
                             key1Info.content?.passphrase?.salt ?: "",
                             key1Info.content?.passphrase?.iterations ?: 0,
-                            null)
+                            null
+                    )
             )
         }
 
@@ -321,7 +327,8 @@ class QuadSTests : InstrumentedTest {
                     keyId,
                     passphrase,
                     emptyKeySigner,
-                    null)
+                    null
+            )
         }
 
         assertAccountData(session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId")
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt
index 14e659e2b606bfa8b434b078206ff95db59d2347..2892cf846411d3dcaf273713d1184de254b02c57 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt
@@ -75,10 +75,12 @@ class SASTest : InstrumentedTest {
         }
         bobVerificationService.addListener(bobListener)
 
-        val txID = aliceVerificationService.beginKeyVerification(VerificationMethod.SAS,
+        val txID = aliceVerificationService.beginKeyVerification(
+                VerificationMethod.SAS,
                 bobSession.myUserId,
                 bobSession.cryptoService().getMyDevice().deviceId,
-                null)
+                null
+        )
         assertNotNull("Alice should have a started transaction", txID)
 
         val aliceKeyTx = aliceVerificationService.getExistingTransaction(bobSession.myUserId, txID!!)
@@ -467,8 +469,10 @@ class SASTest : InstrumentedTest {
         val aliceTx = aliceVerificationService.getExistingTransaction(bobUserId, verificationSAS!!) as SASDefaultVerificationTransaction
         val bobTx = bobVerificationService.getExistingTransaction(aliceSession.myUserId, verificationSAS) as SASDefaultVerificationTransaction
 
-        assertEquals("Should have same SAS", aliceTx.getShortCodeRepresentation(SasMode.DECIMAL),
-                bobTx.getShortCodeRepresentation(SasMode.DECIMAL))
+        assertEquals(
+                "Should have same SAS", aliceTx.getShortCodeRepresentation(SasMode.DECIMAL),
+                bobTx.getShortCodeRepresentation(SasMode.DECIMAL)
+        )
 
         cryptoTestData.cleanUp(testHelper)
     }
@@ -544,7 +548,8 @@ class SASTest : InstrumentedTest {
 
         // Assert that devices are verified
         val bobDeviceInfoFromAlicePOV: CryptoDeviceInfo? = aliceSession.cryptoService().getDeviceInfo(bobUserId, bobDeviceId)
-        val aliceDeviceInfoFromBobPOV: CryptoDeviceInfo? = bobSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceSession.cryptoService().getMyDevice().deviceId)
+        val aliceDeviceInfoFromBobPOV: CryptoDeviceInfo? =
+                bobSession.cryptoService().getDeviceInfo(aliceSession.myUserId, aliceSession.cryptoService().getMyDevice().deviceId)
 
         assertTrue("alice device should be verified from bob point of view", aliceDeviceInfoFromBobPOV!!.isVerified)
         assertTrue("bob device should be verified from alice point of view", bobDeviceInfoFromAlicePOV!!.isVerified)
@@ -611,14 +616,16 @@ class SASTest : InstrumentedTest {
                 requestID!!,
                 cryptoTestData.roomId,
                 bobSession.myUserId,
-                bobSession.sessionParams.deviceId!!)
+                bobSession.sessionParams.deviceId!!
+        )
 
         bobVerificationService.beginKeyVerificationInDMs(
                 VerificationMethod.SAS,
                 requestID!!,
                 cryptoTestData.roomId,
                 aliceSession.myUserId,
-                aliceSession.sessionParams.deviceId!!)
+                aliceSession.sessionParams.deviceId!!
+        )
 
         // we should reach SHOW SAS on both
         var alicePovTx: SasVerificationTransaction?
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt
index 76bf6dc0408aa82365e5c840cb195eb46e118536..d7b4d636fc9be340fb7cb52c6e4da69dcbff5aa9 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeTest.kt
@@ -37,7 +37,8 @@ class QrCodeTest : InstrumentedTest {
             sharedSecret = "MTIzNDU2Nzg"
     )
 
-    private val value1 = "MATRIX\u0002\u0000\u0000\u000DMaTransaction\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢UMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥12345678"
+    private val value1 =
+            "MATRIX\u0002\u0000\u0000\u000DMaTransaction\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢UMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥12345678"
 
     private val qrCode2 = QrCodeData.SelfVerifyingMasterKeyTrusted(
             transactionId = "MaTransaction",
@@ -46,7 +47,8 @@ class QrCodeTest : InstrumentedTest {
             sharedSecret = "MTIzNDU2Nzg"
     )
 
-    private val value2 = "MATRIX\u0002\u0001\u0000\u000DMaTransaction\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢UMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥12345678"
+    private val value2 =
+            "MATRIX\u0002\u0001\u0000\u000DMaTransaction\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢UMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥12345678"
 
     private val qrCode3 = QrCodeData.SelfVerifyingMasterKeyNotTrusted(
             transactionId = "MaTransaction",
@@ -55,7 +57,8 @@ class QrCodeTest : InstrumentedTest {
             sharedSecret = "MTIzNDU2Nzg"
     )
 
-    private val value3 = "MATRIX\u0002\u0002\u0000\u000DMaTransactionMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢U12345678"
+    private val value3 =
+            "MATRIX\u0002\u0002\u0000\u000DMaTransactionMynd¤Ù.ô\u0091XäÏ\u0094ê\u008B«\u009Døl\u000F¿+\u008CË\u0014¤®õÁ\u008BA¥\u0092Ñ0qCú²íq\u0087á®\u0013à\u0098\u0091\u000DÇéoÃ\"_²lq]hC«¢U12345678"
 
     private val sharedSecretByteArray = "12345678".toByteArray(Charsets.ISO_8859_1)
 
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/VerificationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/VerificationTest.kt
index 374d709505311572790f0019f01d2b8dddadde79..df3b2ffe276d2e982eb79963add0dcec97ad1d40 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/VerificationTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/VerificationTest.kt
@@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.crypto.verification.qrcode
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import org.amshove.kluent.shouldBe
 import org.junit.FixMethodOrder
-import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -40,7 +39,6 @@ import kotlin.coroutines.resume
 
 @RunWith(AndroidJUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
-@Ignore("This test is flaky ; see issue #5449")
 class VerificationTest : InstrumentedTest {
 
     data class ExpectedResult(
@@ -175,7 +173,8 @@ class VerificationTest : InstrumentedTest {
                                             )
                                     )
                                 }
-                            }, callback)
+                            }, callback
+                    )
         }
 
         testHelper.doSync<Unit> { callback ->
@@ -191,7 +190,8 @@ class VerificationTest : InstrumentedTest {
                                             )
                                     )
                                 }
-                            }, callback)
+                            }, callback
+                    )
         }
 
         val aliceVerificationService = aliceSession.cryptoService().verificationService()
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt
index ef98ed22c7112328b79ca1512ef0f93170dfc4eb..acb23bf72382776d55b9f2f68eb352220417eaeb 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt
@@ -71,10 +71,12 @@ class MarkdownParserTest : InstrumentedTest {
         testIdentity("")
         testIdentity("a")
         testIdentity("1")
-        testIdentity("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et " +
-                "dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea com" +
-                "modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pari" +
-                "atur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
+        testIdentity(
+                "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et " +
+                        "dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea com" +
+                        "modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pari" +
+                        "atur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
+        )
     }
 
     @Test
@@ -294,16 +296,20 @@ class MarkdownParserTest : InstrumentedTest {
         "$markdownPattern$name$markdownPattern"
                 .let {
                     markdownParser.parse(it)
-                            .expect(expectedText = it,
-                                    expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag>")
+                            .expect(
+                                    expectedText = it,
+                                    expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag>"
+                            )
                 }
 
         // Test twice the same tag
         "$markdownPattern$name$markdownPattern and $markdownPattern$name bis$markdownPattern"
                 .let {
                     markdownParser.parse(it)
-                            .expect(expectedText = it,
-                                    expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag> and <$htmlExpectedTag>$name bis</$htmlExpectedTag>")
+                            .expect(
+                                    expectedText = it,
+                                    expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag> and <$htmlExpectedTag>$name bis</$htmlExpectedTag>"
+                            )
                 }
 
         val textBefore = "a"
@@ -313,48 +319,60 @@ class MarkdownParserTest : InstrumentedTest {
         "$textBefore$markdownPattern$name$markdownPattern"
                 .let {
                     markdownParser.parse(it)
-                            .expect(expectedText = it,
-                                    expectedFormattedText = "$textBefore<$htmlExpectedTag>$name</$htmlExpectedTag>")
+                            .expect(
+                                    expectedText = it,
+                                    expectedFormattedText = "$textBefore<$htmlExpectedTag>$name</$htmlExpectedTag>"
+                            )
                 }
 
         // With text before and space
         "$textBefore $markdownPattern$name$markdownPattern"
                 .let {
                     markdownParser.parse(it)
-                            .expect(expectedText = it,
-                                    expectedFormattedText = "$textBefore <$htmlExpectedTag>$name</$htmlExpectedTag>")
+                            .expect(
+                                    expectedText = it,
+                                    expectedFormattedText = "$textBefore <$htmlExpectedTag>$name</$htmlExpectedTag>"
+                            )
                 }
 
         // With sticked text after
         "$markdownPattern$name$markdownPattern$textAfter"
                 .let {
                     markdownParser.parse(it)
-                            .expect(expectedText = it,
-                                    expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag>$textAfter")
+                            .expect(
+                                    expectedText = it,
+                                    expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag>$textAfter"
+                            )
                 }
 
         // With space and text after
         "$markdownPattern$name$markdownPattern $textAfter"
                 .let {
                     markdownParser.parse(it)
-                            .expect(expectedText = it,
-                                    expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag> $textAfter")
+                            .expect(
+                                    expectedText = it,
+                                    expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag> $textAfter"
+                            )
                 }
 
         // With sticked text before and text after
         "$textBefore$markdownPattern$name$markdownPattern$textAfter"
                 .let {
                     markdownParser.parse(it)
-                            .expect(expectedText = it,
-                                    expectedFormattedText = "a<$htmlExpectedTag>$name</$htmlExpectedTag>$textAfter")
+                            .expect(
+                                    expectedText = it,
+                                    expectedFormattedText = "a<$htmlExpectedTag>$name</$htmlExpectedTag>$textAfter"
+                            )
                 }
 
         // With text before and after, with spaces
         "$textBefore $markdownPattern$name$markdownPattern $textAfter"
                 .let {
                     markdownParser.parse(it)
-                            .expect(expectedText = it,
-                                    expectedFormattedText = "$textBefore <$htmlExpectedTag>$name</$htmlExpectedTag> $textAfter")
+                            .expect(
+                                    expectedText = it,
+                                    expectedFormattedText = "$textBefore <$htmlExpectedTag>$name</$htmlExpectedTag> $textAfter"
+                            )
                 }
     }
 
@@ -366,16 +384,20 @@ class MarkdownParserTest : InstrumentedTest {
         "$markdownPattern$name\n$name$markdownPattern"
                 .let {
                     markdownParser.parse(it)
-                            .expect(expectedText = it,
-                                    expectedFormattedText = "<$htmlExpectedTag>$name$softBreak$name</$htmlExpectedTag>")
+                            .expect(
+                                    expectedText = it,
+                                    expectedFormattedText = "<$htmlExpectedTag>$name$softBreak$name</$htmlExpectedTag>"
+                            )
                 }
 
         // With new line between two blocks
         "$markdownPattern$name$markdownPattern\n$markdownPattern$name$markdownPattern"
                 .let {
                     markdownParser.parse(it)
-                            .expect(expectedText = it,
-                                    expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag><br /><$htmlExpectedTag>$name</$htmlExpectedTag>")
+                            .expect(
+                                    expectedText = it,
+                                    expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag><br /><$htmlExpectedTag>$name</$htmlExpectedTag>"
+                            )
                 }
     }
 
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/util/JsonCanonicalizerTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/util/JsonCanonicalizerTest.kt
index d38afc6b62f53a7092d00fb4cb1b4a02db58f3f4..67eafea55d998b1eccd7f11e2840b6eb02fe3024 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/util/JsonCanonicalizerTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/util/JsonCanonicalizerTest.kt
@@ -39,27 +39,35 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
                 """{"a":["c":"b","d":"e"]}""",
                 """{"a":["d":"b","c":"e"]}"""
         ).forEach {
-            assertEquals(it,
-                    JsonCanonicalizer.canonicalize(it))
+            assertEquals(
+                    it,
+                    JsonCanonicalizer.canonicalize(it)
+            )
         }
     }
 
     @Test
     fun reorderTest() {
-        assertEquals("""{"a":true,"b":false}""",
-                JsonCanonicalizer.canonicalize("""{"b":false,"a":true}"""))
+        assertEquals(
+                """{"a":true,"b":false}""",
+                JsonCanonicalizer.canonicalize("""{"b":false,"a":true}""")
+        )
     }
 
     @Test
     fun realSampleTest() {
-        assertEquals("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX\/FjTRLfySgs65ldYyomm7PIx6U"},"user_id":"@benoitx:matrix.org"}""",
-                JsonCanonicalizer.canonicalize("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","user_id":"@benoitx:matrix.org","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX/FjTRLfySgs65ldYyomm7PIx6U"}}"""))
+        assertEquals(
+                """{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX\/FjTRLfySgs65ldYyomm7PIx6U"},"user_id":"@benoitx:matrix.org"}""",
+                JsonCanonicalizer.canonicalize("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","user_id":"@benoitx:matrix.org","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX/FjTRLfySgs65ldYyomm7PIx6U"}}""")
+        )
     }
 
     @Test
     fun doubleQuoteTest() {
-        assertEquals("{\"a\":\"\\\"\"}",
-                JsonCanonicalizer.canonicalize("{\"a\":\"\\\"\"}"))
+        assertEquals(
+                "{\"a\":\"\\\"\"}",
+                JsonCanonicalizer.canonicalize("{\"a\":\"\\\"\"}")
+        )
     }
 
     /* ==========================================================================================
@@ -68,38 +76,52 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
 
     @Test
     fun matrixOrg001Test() {
-        assertEquals("""{}""",
-                JsonCanonicalizer.canonicalize("""{}"""))
+        assertEquals(
+                """{}""",
+                JsonCanonicalizer.canonicalize("""{}""")
+        )
     }
 
     @Test
     fun matrixOrg002Test() {
-        assertEquals("""{"one":1,"two":"Two"}""",
-                JsonCanonicalizer.canonicalize("""{
+        assertEquals(
+                """{"one":1,"two":"Two"}""",
+                JsonCanonicalizer.canonicalize(
+                        """{
     "one": 1,
     "two": "Two"
-}"""))
+}"""
+                )
+        )
     }
 
     @Test
     fun matrixOrg003Test() {
-        assertEquals("""{"a":"1","b":"2"}""",
-                JsonCanonicalizer.canonicalize("""{
+        assertEquals(
+                """{"a":"1","b":"2"}""",
+                JsonCanonicalizer.canonicalize(
+                        """{
     "b": "2",
     "a": "1"
-}"""))
+}"""
+                )
+        )
     }
 
     @Test
     fun matrixOrg004Test() {
-        assertEquals("""{"a":"1","b":"2"}""",
-                JsonCanonicalizer.canonicalize("""{"b":"2","a":"1"}"""))
+        assertEquals(
+                """{"a":"1","b":"2"}""",
+                JsonCanonicalizer.canonicalize("""{"b":"2","a":"1"}""")
+        )
     }
 
     @Test
     fun matrixOrg005Test() {
-        assertEquals("""{"auth":{"mxid":"@john.doe:example.com","profile":{"display_name":"John Doe","three_pids":[{"address":"john.doe@example.org","medium":"email"},{"address":"123456789","medium":"msisdn"}]},"success":true}}""",
-                JsonCanonicalizer.canonicalize("""{
+        assertEquals(
+                """{"auth":{"mxid":"@john.doe:example.com","profile":{"display_name":"John Doe","three_pids":[{"address":"john.doe@example.org","medium":"email"},{"address":"123456789","medium":"msisdn"}]},"success":true}}""",
+                JsonCanonicalizer.canonicalize(
+                        """{
     "auth": {
         "success": true,
         "mxid": "@john.doe:example.com",
@@ -117,37 +139,53 @@ internal class JsonCanonicalizerTest : InstrumentedTest {
             ]
         }
     }
-}"""))
+}"""
+                )
+        )
     }
 
     @Test
     fun matrixOrg006Test() {
-        assertEquals("""{"a":"日本語"}""",
-                JsonCanonicalizer.canonicalize("""{
+        assertEquals(
+                """{"a":"日本語"}""",
+                JsonCanonicalizer.canonicalize(
+                        """{
     "a": "日本語"
-}"""))
+}"""
+                )
+        )
     }
 
     @Test
     fun matrixOrg007Test() {
-        assertEquals("""{"日":1,"本":2}""",
-                JsonCanonicalizer.canonicalize("""{
+        assertEquals(
+                """{"日":1,"本":2}""",
+                JsonCanonicalizer.canonicalize(
+                        """{
     "本": 2,
     "æ—¥": 1
-}"""))
+}"""
+                )
+        )
     }
 
     @Test
     fun matrixOrg008Test() {
-        assertEquals("""{"a":"æ—¥"}""",
-                JsonCanonicalizer.canonicalize("{\"a\": \"\u65E5\"}"))
+        assertEquals(
+                """{"a":"æ—¥"}""",
+                JsonCanonicalizer.canonicalize("{\"a\": \"\u65E5\"}")
+        )
     }
 
     @Test
     fun matrixOrg009Test() {
-        assertEquals("""{"a":null}""",
-                JsonCanonicalizer.canonicalize("""{
+        assertEquals(
+                """{"a":null}""",
+                JsonCanonicalizer.canonicalize(
+                        """{
     "a": null
-}"""))
+}"""
+                )
+        )
     }
 }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/ordering/StringOrderTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/ordering/StringOrderTest.kt
index 728986441a0589e8f5dbd0af0f716b510bf79049..b5870ebf69798c6274ee89a939f849bbedd0ebaf 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/ordering/StringOrderTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/ordering/StringOrderTest.kt
@@ -26,9 +26,18 @@ class StringOrderTest {
 
     @Test
     fun testbasing() {
-        assertEquals("a", StringOrderUtils.baseToString(StringOrderUtils.stringToBase("a", StringOrderUtils.DEFAULT_ALPHABET), StringOrderUtils.DEFAULT_ALPHABET))
-        assertEquals("element", StringOrderUtils.baseToString(StringOrderUtils.stringToBase("element", StringOrderUtils.DEFAULT_ALPHABET), StringOrderUtils.DEFAULT_ALPHABET))
-        assertEquals("matrix", StringOrderUtils.baseToString(StringOrderUtils.stringToBase("matrix", StringOrderUtils.DEFAULT_ALPHABET), StringOrderUtils.DEFAULT_ALPHABET))
+        assertEquals(
+                "a",
+                StringOrderUtils.baseToString(StringOrderUtils.stringToBase("a", StringOrderUtils.DEFAULT_ALPHABET), StringOrderUtils.DEFAULT_ALPHABET)
+        )
+        assertEquals(
+                "element",
+                StringOrderUtils.baseToString(StringOrderUtils.stringToBase("element", StringOrderUtils.DEFAULT_ALPHABET), StringOrderUtils.DEFAULT_ALPHABET)
+        )
+        assertEquals(
+                "matrix",
+                StringOrderUtils.baseToString(StringOrderUtils.stringToBase("matrix", StringOrderUtils.DEFAULT_ALPHABET), StringOrderUtils.DEFAULT_ALPHABET)
+        )
     }
 
     @Test
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt
index f6e08a576e20b3fcf29a88f2689ec05d6bd635cc..a2984dd27e2de8d27d082e5df6579049a8f3e456 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt
@@ -59,7 +59,8 @@ class ThreadMessagingTest : InstrumentedTest {
         val sentMessages = commonTestHelper.sendTextMessage(
                 room = aliceRoom,
                 message = textMessage,
-                nbOfMessages = 1)
+                nbOfMessages = 1
+        )
 
         val initMessage = sentMessages.first()
 
@@ -73,7 +74,8 @@ class ThreadMessagingTest : InstrumentedTest {
                 room = aliceRoom,
                 message = "Reply In the above thread",
                 numberOfMessages = 1,
-                rootThreadEventId = initMessage.root.eventId.orEmpty())
+                rootThreadEventId = initMessage.root.eventId.orEmpty()
+        )
 
         val replyInThread = repliesInThread.first()
         replyInThread.root.isThread().shouldBeTrue()
@@ -116,7 +118,8 @@ class ThreadMessagingTest : InstrumentedTest {
         val sentMessages = commonTestHelper.sendTextMessage(
                 room = aliceRoom,
                 message = textMessage,
-                nbOfMessages = 1)
+                nbOfMessages = 1
+        )
 
         val initMessage = sentMessages.first()
 
@@ -134,7 +137,8 @@ class ThreadMessagingTest : InstrumentedTest {
                 room = bobRoom,
                 message = "Reply In the above thread",
                 numberOfMessages = 1,
-                rootThreadEventId = initMessage.root.eventId.orEmpty())
+                rootThreadEventId = initMessage.root.eventId.orEmpty()
+        )
 
         val replyInThread = repliesInThread.first()
         replyInThread.root.isThread().shouldBeTrue()
@@ -190,7 +194,8 @@ class ThreadMessagingTest : InstrumentedTest {
         val sentMessages = commonTestHelper.sendTextMessage(
                 room = aliceRoom,
                 message = textMessage,
-                nbOfMessages = 5)
+                nbOfMessages = 5
+        )
 
         sentMessages.forEach {
             it.root.isThread().shouldBeFalse()
@@ -206,7 +211,8 @@ class ThreadMessagingTest : InstrumentedTest {
                 room = aliceRoom,
                 message = "Reply In the above thread",
                 numberOfMessages = 40,
-                rootThreadEventId = selectedInitMessage.root.eventId.orEmpty())
+                rootThreadEventId = selectedInitMessage.root.eventId.orEmpty()
+        )
 
         repliesInThread.forEach {
             it.root.isThread().shouldBeTrue()
@@ -253,7 +259,8 @@ class ThreadMessagingTest : InstrumentedTest {
         val sentMessages = commonTestHelper.sendTextMessage(
                 room = aliceRoom,
                 message = textMessage,
-                nbOfMessages = 5)
+                nbOfMessages = 5
+        )
 
         sentMessages.forEach {
             it.root.isThread().shouldBeFalse()
@@ -270,7 +277,8 @@ class ThreadMessagingTest : InstrumentedTest {
                 room = aliceRoom,
                 message = "Alice reply In the above second thread message",
                 numberOfMessages = 35,
-                rootThreadEventId = secondMessage.root.eventId.orEmpty())
+                rootThreadEventId = secondMessage.root.eventId.orEmpty()
+        )
 
         // Let's reply in timeline to that message from another user
         val bobSession = cryptoTestData.secondSession!!
@@ -282,14 +290,16 @@ class ThreadMessagingTest : InstrumentedTest {
                 room = bobRoom,
                 message = "Bob reply In the above first thread message",
                 numberOfMessages = 42,
-                rootThreadEventId = firstMessage.root.eventId.orEmpty())
+                rootThreadEventId = firstMessage.root.eventId.orEmpty()
+        )
 
         // Bob will also reply in second thread 5 times
         val bobThreadRepliesInSecondMessage = commonTestHelper.replyInThreadMessage(
                 room = bobRoom,
                 message = "Another Bob reply In the above second thread message",
                 numberOfMessages = 20,
-                rootThreadEventId = secondMessage.root.eventId.orEmpty())
+                rootThreadEventId = secondMessage.root.eventId.orEmpty()
+        )
 
         aliceThreadRepliesInSecondMessage.forEach {
             it.root.isThread().shouldBeTrue()
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt
index 27d3fdc85615fe8e106ac69868560b04322ab088..94b2ba55a3456bdbacd1e47958b96a55b6a0bd0f 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt
@@ -68,7 +68,8 @@ internal class ChunkEntityTest : InstrumentedTest {
                     roomId = ROOM_ID,
                     eventEntity = fakeEvent,
                     direction = PaginationDirection.FORWARDS,
-                    roomMemberContentsByUser = emptyMap())
+                    roomMemberContentsByUser = emptyMap()
+            )
             chunk.timelineEvents.size shouldBeEqualTo 1
         }
     }
@@ -84,12 +85,14 @@ internal class ChunkEntityTest : InstrumentedTest {
                     roomId = ROOM_ID,
                     eventEntity = fakeEvent,
                     direction = PaginationDirection.FORWARDS,
-                    roomMemberContentsByUser = emptyMap())
+                    roomMemberContentsByUser = emptyMap()
+            )
             chunk.addTimelineEvent(
                     roomId = ROOM_ID,
                     eventEntity = fakeEvent,
                     direction = PaginationDirection.FORWARDS,
-                    roomMemberContentsByUser = emptyMap())
+                    roomMemberContentsByUser = emptyMap()
+            )
             chunk.timelineEvents.size shouldBeEqualTo 1
         }
     }
@@ -162,7 +165,8 @@ internal class ChunkEntityTest : InstrumentedTest {
                     roomId = roomId,
                     eventEntity = fakeEvent,
                     direction = direction,
-                    roomMemberContentsByUser = emptyMap())
+                    roomMemberContentsByUser = emptyMap()
+            )
         }
     }
 
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt
index 3864ea1cd1b28941f485677c719e2deff006a6af..d5b4a07fc0fd19a43c625acbfeb15c14a8c0d12a 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt
@@ -71,7 +71,8 @@ class TimelineForwardPaginationTest : InstrumentedTest {
         val sentMessages = commonTestHelper.sendTextMessage(
                 roomFromAlicePOV,
                 message,
-                numberOfMessagesToSend)
+                numberOfMessagesToSend
+        )
 
         // Alice clear the cache and restart the sync
         commonTestHelper.clearCacheAndSync(aliceSession)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt
index 5d09b74e6c3f8773ef10ffea907996418dfd8524..6e5fed8df9f2f2c11125f525f80fc0e07ca6db14 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt
@@ -94,7 +94,8 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
         val firstMessageFromAliceId = commonTestHelper.sendTextMessage(
                 roomFromAlicePOV,
                 firstMessage,
-                30)
+                30
+        )
                 .last()
                 .eventId
 
@@ -130,7 +131,8 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
         commonTestHelper.sendTextMessage(
                 roomFromAlicePOV,
                 secondMessage,
-                30)
+                30
+        )
 
         // Bob start to sync
         bobSession.startSync(true)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineSimpleBackPaginationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineSimpleBackPaginationTest.kt
index 251b2c614cd7302c1738fb7ba7ee86f0506b5df8..42f710d7cf431f2a90f14fb56e8b61b05cea4674 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineSimpleBackPaginationTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineSimpleBackPaginationTest.kt
@@ -64,7 +64,8 @@ class TimelineSimpleBackPaginationTest : InstrumentedTest {
         commonTestHelper.sendTextMessage(
                 roomFromAlicePOV,
                 message,
-                numberOfMessagesToSent)
+                numberOfMessagesToSent
+        )
 
         val bobTimeline = roomFromBobPOV.timelineService().createTimeline(null, TimelineSettings(30))
         bobTimeline.start()
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt
index ab0bbe7f73f9450fc913577e3f3c1c417bbb93de..e17b7efbd6d9d348c39ebb02ba9c99fc625b1bdc 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt
@@ -85,7 +85,8 @@ class SearchMessagesTest : InstrumentedTest {
         commonTestHelper.sendTextMessage(
                 roomFromAlicePOV,
                 MESSAGE,
-                2)
+                2
+        )
 
         val data = commonTestHelper.runBlockingTest {
             block.invoke(cryptoTestData)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt
index d2c8b52fc7693ac08e1eab3c4c7e9b953a2395ab..6a17cb74add602e49100d148a961a6615fe2c450 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt
@@ -177,21 +177,27 @@ class SpaceHierarchyTest : InstrumentedTest {
         val commonTestHelper = CommonTestHelper(context())
         val session = commonTestHelper.createAccount("John", SessionTestParams(true))
 
-        val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
+        val spaceAInfo = createPublicSpace(
+                session, "SpaceA", listOf(
                 Triple("A1", true /*auto-join*/, true/*canonical*/),
                 Triple("A2", true, true)
-        ))
+        )
+        )
 
-        /* val spaceBInfo = */ createPublicSpace(session, "SpaceB", listOf(
+        /* val spaceBInfo = */ createPublicSpace(
+                session, "SpaceB", listOf(
                 Triple("B1", true /*auto-join*/, true/*canonical*/),
                 Triple("B2", true, true),
                 Triple("B3", true, true)
-        ))
+        )
+        )
 
-        val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
+        val spaceCInfo = createPublicSpace(
+                session, "SpaceC", listOf(
                 Triple("C1", true /*auto-join*/, true/*canonical*/),
                 Triple("C2", true, true)
-        ))
+        )
+        )
 
         // add C as a subspace of A
         val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
@@ -254,15 +260,19 @@ class SpaceHierarchyTest : InstrumentedTest {
         val commonTestHelper = CommonTestHelper(context())
         val session = commonTestHelper.createAccount("John", SessionTestParams(true))
 
-        val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
+        val spaceAInfo = createPublicSpace(
+                session, "SpaceA", listOf(
                 Triple("A1", true /*auto-join*/, true/*canonical*/),
                 Triple("A2", true, true)
-        ))
+        )
+        )
 
-        val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
+        val spaceCInfo = createPublicSpace(
+                session, "SpaceC", listOf(
                 Triple("C1", true /*auto-join*/, true/*canonical*/),
                 Triple("C2", true, true)
-        ))
+        )
+        )
 
         // add C as a subspace of A
         val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
@@ -296,16 +306,20 @@ class SpaceHierarchyTest : InstrumentedTest {
         val commonTestHelper = CommonTestHelper(context())
         val session = commonTestHelper.createAccount("John", SessionTestParams(true))
 
-        val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
+        val spaceAInfo = createPublicSpace(
+                session, "SpaceA", listOf(
                 Triple("A1", true /*auto-join*/, true/*canonical*/),
                 Triple("A2", true, true)
-        ))
+        )
+        )
 
-        val spaceBInfo = createPublicSpace(session, "SpaceB", listOf(
+        val spaceBInfo = createPublicSpace(
+                session, "SpaceB", listOf(
                 Triple("B1", true /*auto-join*/, true/*canonical*/),
                 Triple("B2", true, true),
                 Triple("B3", true, true)
-        ))
+        )
+        )
 
         // add B as a subspace of A
         val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
@@ -315,10 +329,12 @@ class SpaceHierarchyTest : InstrumentedTest {
             session.spaceService().setSpaceParent(spaceBInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
         }
 
-        val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
+        val spaceCInfo = createPublicSpace(
+                session, "SpaceC", listOf(
                 Triple("C1", true /*auto-join*/, true/*canonical*/),
                 Triple("C2", true, true)
-        ))
+        )
+        )
 
         commonTestHelper.waitWithLatch { latch ->
 
@@ -446,21 +462,27 @@ class SpaceHierarchyTest : InstrumentedTest {
         val commonTestHelper = CommonTestHelper(context())
         val session = commonTestHelper.createAccount("John", SessionTestParams(true))
 
-        /* val spaceAInfo = */ createPublicSpace(session, "SpaceA", listOf(
+        /* val spaceAInfo = */ createPublicSpace(
+                session, "SpaceA", listOf(
                 Triple("A1", true /*auto-join*/, true/*canonical*/),
                 Triple("A2", true, true)
-        ))
+        )
+        )
 
-        val spaceBInfo = createPublicSpace(session, "SpaceB", listOf(
+        val spaceBInfo = createPublicSpace(
+                session, "SpaceB", listOf(
                 Triple("B1", true /*auto-join*/, true/*canonical*/),
                 Triple("B2", true, true),
                 Triple("B3", true, true)
-        ))
+        )
+        )
 
-        val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
+        val spaceCInfo = createPublicSpace(
+                session, "SpaceC", listOf(
                 Triple("C1", true /*auto-join*/, true/*canonical*/),
                 Triple("C2", true, true)
-        ))
+        )
+        )
 
         val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
 
@@ -494,10 +516,12 @@ class SpaceHierarchyTest : InstrumentedTest {
         val aliceSession = commonTestHelper.createAccount("Alice", SessionTestParams(true))
         val bobSession = commonTestHelper.createAccount("Bib", SessionTestParams(true))
 
-        val spaceAInfo = createPrivateSpace(aliceSession, "Private Space A", listOf(
+        val spaceAInfo = createPrivateSpace(
+                aliceSession, "Private Space A", listOf(
                 Triple("General", true /*suggested*/, true/*canonical*/),
                 Triple("Random", true, true)
-        ))
+        )
+        )
 
         commonTestHelper.runBlockingTest {
             aliceSession.getRoom(spaceAInfo.spaceId)!!.membershipService().invite(bobSession.myUserId, null)
diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.kt
index 0efecbbe8a9946a0b46a31c00337e33cf5cd1ebd..83fcae7190b35c978596d7a745eb60abaddcaff5 100644
--- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.kt
+++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.kt
@@ -28,8 +28,12 @@ internal class MathsHtmlNodeRenderer(private val context: HtmlNodeRendererContex
         val display = node.javaClass == DisplayMaths::class.java
         val contents = node.firstChild // should be the only child
         val latex = (contents as Text).literal
-        val attributes = context.extendAttributes(node, if (display) "div" else "span", Collections.singletonMap("data-mx-maths",
-                latex))
+        val attributes = context.extendAttributes(
+                node, if (display) "div" else "span", Collections.singletonMap(
+                "data-mx-maths",
+                latex
+        )
+        )
         html.tag(if (display) "div" else "span", attributes)
         html.tag("code")
         context.render(contents)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt
index 217f7e3da81361100540b2baa43f25eb16b2b13f..979201706b20cb838744b7764c8db745589239f7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt
@@ -38,15 +38,18 @@ import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
 import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory
 import org.matrix.olm.OlmManager
 import java.util.concurrent.Executors
-import java.util.concurrent.atomic.AtomicBoolean
 import javax.inject.Inject
 
 /**
  * This is the main entry point to the matrix sdk.
  * <br/>
- * See [Companion.createInstance] to create an instance. The app should create and manage the instance itself.
+ *
+ * The constructor creates a new instance of Matrix, it's recommended to manage this instance as a singleton.
+ *
+ * @param context the application context
+ * @param matrixConfiguration global configuration that will be used for every [org.matrix.android.sdk.api.session.Session]
  */
-class Matrix private constructor(context: Context, matrixConfiguration: MatrixConfiguration) {
+class Matrix(context: Context, matrixConfiguration: MatrixConfiguration) {
 
     @Inject internal lateinit var legacySessionImporter: LegacySessionImporter
     @Inject internal lateinit var authenticationService: AuthenticationService
@@ -61,87 +64,72 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
     @Inject internal lateinit var lightweightSettingsStorage: LightweightSettingsStorage
 
     init {
-        Monarchy.init(context)
-        DaggerMatrixComponent.factory().create(context, matrixConfiguration).inject(this)
-        if (context.applicationContext !is Configuration.Provider) {
+        val appContext = context.applicationContext
+        Monarchy.init(appContext)
+        DaggerMatrixComponent.factory().create(appContext, matrixConfiguration).inject(this)
+        if (appContext !is Configuration.Provider) {
             val configuration = Configuration.Builder()
                     .setExecutor(Executors.newCachedThreadPool())
                     .setWorkerFactory(matrixWorkerFactory)
                     .build()
-            WorkManager.initialize(context, configuration)
+            WorkManager.initialize(appContext, configuration)
         }
         ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
     }
 
+    /**
+     * Return the User Agent used for any request that the SDK is making to the homeserver.
+     * There is no way to change the user agent at the moment.
+     */
     fun getUserAgent() = userAgentHolder.userAgent
 
+    /**
+     * Return the AuthenticationService.
+     */
     fun authenticationService() = authenticationService
 
+    /**
+     * Return the RawService.
+     */
     fun rawService() = rawService
 
+    /**
+     * Return the LightweightSettingsStorage.
+     */
     fun lightweightSettingsStorage() = lightweightSettingsStorage
 
+    /**
+     * Return the HomeServerHistoryService.
+     */
     fun homeServerHistoryService() = homeServerHistoryService
 
+    /**
+     * Return the legacy session importer, useful if you want to migrate an app, which was using the legacy Matrix Android Sdk.
+     */
     fun legacySessionImporter() = legacySessionImporter
 
-    fun workerFactory(): WorkerFactory = matrixWorkerFactory
+    /**
+     * Get the worker factory. The returned value has to be provided to `WorkConfiguration.Builder()`.
+     */
+    fun getWorkerFactory(): WorkerFactory = matrixWorkerFactory
 
+    /**
+     * Register an API interceptor, to be able to be notified when the specified API got a response.
+     */
     fun registerApiInterceptorListener(path: ApiPath, listener: ApiInterceptorListener) {
         apiInterceptor.addListener(path, listener)
     }
 
+    /**
+     * Un-register an API interceptor.
+     */
     fun unregisterApiInterceptorListener(path: ApiPath, listener: ApiInterceptorListener) {
         apiInterceptor.removeListener(path, listener)
     }
 
     companion object {
-
-        private lateinit var instance: Matrix
-        private val isInit = AtomicBoolean(false)
-
-        /**
-         * Creates a new instance of Matrix, it's recommended to manage this instance as a singleton.
-         * To make use of the built in singleton use Matrix.initialize() and/or Matrix.getInstance(context) instead
-         **/
-        fun createInstance(context: Context, matrixConfiguration: MatrixConfiguration): Matrix {
-            return Matrix(context.applicationContext, matrixConfiguration)
-        }
-
-        /**
-         * Initializes a singleton instance of Matrix for the given MatrixConfiguration
-         * This instance will be returned by Matrix.getInstance(context)
-         */
-        @Deprecated("Use Matrix.createInstance and manage the instance manually")
-        fun initialize(context: Context, matrixConfiguration: MatrixConfiguration) {
-            if (isInit.compareAndSet(false, true)) {
-                instance = Matrix(context.applicationContext, matrixConfiguration)
-            }
-        }
-
-        /**
-         * Either provides an already initialized singleton Matrix instance or queries the application context for a MatrixConfiguration.Provider
-         * to lazily create and store the instance.
-         */
-        @Suppress("deprecation") // suppressing warning as this method is unused but is still provided for SDK clients
-        @Deprecated("Use Matrix.createInstance and manage the instance manually")
-        fun getInstance(context: Context): Matrix {
-            if (isInit.compareAndSet(false, true)) {
-                val appContext = context.applicationContext
-                if (appContext is MatrixConfiguration.Provider) {
-                    val matrixConfiguration = (appContext as MatrixConfiguration.Provider).providesMatrixConfiguration()
-                    instance = Matrix(appContext, matrixConfiguration)
-                } else {
-                    throw IllegalStateException("Matrix is not initialized properly." +
-                            " If you want to manage your own Matrix instance use Matrix.createInstance" +
-                            " otherwise you should call Matrix.initialize or let your application implement MatrixConfiguration.Provider.")
-                }
-            }
-            return instance
-        }
-
         /**
-         * @return a String with details about the Matrix SDK version
+         * @return a String with details about the Matrix SDK version.
          */
         fun getSdkVersion(): String {
             return BuildConfig.SDK_VERSION + " (" + BuildConfig.GIT_SDK_REVISION + ")"
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixCallback.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixCallback.kt
index 166ba8eab9942f87565329a65a0805efe012eb9d..7cd450b5ad4dc512233ce652c6e46bcaf43de869 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixCallback.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixCallback.kt
@@ -23,7 +23,7 @@ package org.matrix.android.sdk.api
 interface MatrixCallback<in T> {
 
     /**
-     * On success method, default to no-op
+     * On success method, default to no-op.
      * @param data the data successfully returned from the async function
      */
     fun onSuccess(data: T) {
@@ -31,7 +31,7 @@ interface MatrixCallback<in T> {
     }
 
     /**
-     * On failure method, default to no-op
+     * On failure method, default to no-op.
      * @param failure the failure data returned from the async function
      */
     fun onFailure(failure: Throwable) {
@@ -40,6 +40,6 @@ interface MatrixCallback<in T> {
 }
 
 /**
- * Basic no op implementation
+ * Basic no op implementation.
  */
 class NoOpMatrixCallback<T> : MatrixCallback<T>
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt
index f8472319fdc30456a9316c1a9d094cb9a32b0126..21106fba6c3d6d7f724310c1cf051961082200f5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt
@@ -46,7 +46,7 @@ data class MatrixConfiguration(
          */
         val proxy: Proxy? = null,
         /**
-         * TLS versions and cipher suites limitation for unauthenticated requests
+         * TLS versions and cipher suites limitation for unauthenticated requests.
          */
         val connectionSpec: ConnectionSpec = ConnectionSpec.RESTRICTED_TLS,
         /**
@@ -62,16 +62,7 @@ data class MatrixConfiguration(
          */
         val roomDisplayNameFallbackProvider: RoomDisplayNameFallbackProvider,
         /**
-         * Thread messages default enable/disabled value
+         * Thread messages default enable/disabled value.
          */
         val threadMessagesEnabledDefault: Boolean = false,
-) {
-
-    /**
-     * Can be implemented by your Application class.
-     */
-    @Deprecated("Use Matrix.createInstance and manage the instance manually instead of Matrix.getInstance")
-    interface Provider {
-        fun providesMatrixConfiguration(): MatrixConfiguration
-    }
-}
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConstants.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConstants.kt
index 49520f36785e3d86bc2511f1bf30bfe6e351bea1..33a820ddde26808df92b24b216fe16e7cc314ee2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConstants.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConstants.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.api
 
 /**
- * This object define some global constants regarding the Matrix specification
+ * This object define some global constants regarding the Matrix specification.
  */
 object MatrixConstants {
     /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt
index 2a26b612fb082e45a3e73716c28d2fd4eb3057d2..867e066e604f83195213c57cd781882a3e570432 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt
@@ -147,7 +147,7 @@ object MatrixPatterns {
     }
 
     /**
-     * Extract server name from a matrix id
+     * Extract server name from a matrix id.
      *
      * @param matrixId
      * @return null if not found or if matrixId is null
@@ -172,7 +172,7 @@ object MatrixPatterns {
     }
 
     /**
-     * Return the domain form a userId
+     * Return the domain form a userId.
      * Examples:
      * - "@alice:domain.org".getDomain() will return "domain.org"
      * - "@bob:domain.org:3455".getDomain() will return "domain.org:3455"
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixUrls.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixUrls.kt
index 4a41eaec4a18b37cdd7cd43a829de18953dcf180..7958186f167f55564b2a989b077febb0cf21f8bd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixUrls.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixUrls.kt
@@ -17,21 +17,21 @@
 package org.matrix.android.sdk.api
 
 /**
- * This class contains pattern to match Matrix Url, aka mxc urls
+ * This class contains pattern to match Matrix Url, aka mxc urls.
  */
 object MatrixUrls {
     /**
-     * "mxc" scheme, including "://". So "mxc://"
+     * "mxc" scheme, including "://". So "mxc://".
      */
     const val MATRIX_CONTENT_URI_SCHEME = "mxc://"
 
     /**
-     * Return true if the String starts with "mxc://"
+     * Return true if the String starts with "mxc://".
      */
     fun String.isMxcUrl() = startsWith(MATRIX_CONTENT_URI_SCHEME)
 
     /**
-     * Remove the "mxc://" prefix. No op if the String is not a Mxc URL
+     * Remove the "mxc://" prefix. No op if the String is not a Mxc URL.
      */
     fun String.removeMxcPrefix() = removePrefix(MATRIX_CONTENT_URI_SCHEME)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt
index 9cb784c9c02321c8f0ba93e7e22d6b6b6500160a..5a19df90c4f99eb105f630241bc411ad541cdf1e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt
@@ -40,12 +40,12 @@ interface AuthenticationService {
     suspend fun getLoginFlowOfSession(sessionId: String): LoginFlowResult
 
     /**
-     * Get a SSO url
+     * Get a SSO url.
      */
     fun getSsoUrl(redirectUrl: String, deviceId: String?, providerId: String?): String?
 
     /**
-     * Get the sign in or sign up fallback URL
+     * Get the sign in or sign up fallback URL.
      */
     fun getFallbackUrl(forSignIn: Boolean, deviceId: String?): String?
 
@@ -64,17 +64,17 @@ interface AuthenticationService {
     fun getRegistrationWizard(): RegistrationWizard
 
     /**
-     * True when login and password has been sent with success to the homeserver
+     * True when login and password has been sent with success to the homeserver.
      */
     val isRegistrationStarted: Boolean
 
     /**
-     * Cancel pending login or pending registration
+     * Cancel pending login or pending registration.
      */
     suspend fun cancelPendingLoginOrRegistration()
 
     /**
-     * Reset all pending settings, including current HomeServerConnectionConfig
+     * Reset all pending settings, including current HomeServerConnectionConfig.
      */
     suspend fun reset()
 
@@ -91,20 +91,20 @@ interface AuthenticationService {
     fun getLastAuthenticatedSession(): Session?
 
     /**
-     * Create a session after a SSO successful login
+     * Create a session after a SSO successful login.
      */
     suspend fun createSessionFromSso(homeServerConnectionConfig: HomeServerConnectionConfig,
                                      credentials: Credentials): Session
 
     /**
-     * Perform a wellknown request, using the domain from the matrixId
+     * Perform a wellknown request, using the domain from the matrixId.
      */
     suspend fun getWellKnownData(matrixId: String,
                                  homeServerConnectionConfig: HomeServerConnectionConfig?): WellknownResult
 
     /**
-     * Authenticate with a matrixId and a password
-     * Usually call this after a successful call to getWellKnownData()
+     * Authenticate with a matrixId and a password.
+     * Usually call this after a successful call to getWellKnownData().
      * @param homeServerConnectionConfig the information about the homeserver and other configuration
      * @param matrixId the matrixId of the user
      * @param password the password of the account
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/TokenBasedAuth.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/TokenBasedAuth.kt
index e522352c3870735644f295556c5815651664c765..2c99ced995c2b73c8df73cd5910bd445855a8669 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/TokenBasedAuth.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/TokenBasedAuth.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
 
 /**
- * This class provides the authentication data by using user and password
+ * This class provides the authentication data by using user and password.
  */
 @JsonClass(generateAdapter = true)
 data class TokenBasedAuth(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UserPasswordAuth.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UserPasswordAuth.kt
index e985c5f08abfdeee95c5dcc214f4af169024f9a2..8cd5b5e6eb890aff6bf47700dbf2a803c9a5a280 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UserPasswordAuth.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/UserPasswordAuth.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
 
 /**
- * This class provides the authentication data by using user and password
+ * This class provides the authentication data by using user and password.
  */
 @JsonClass(generateAdapter = true)
 data class UserPasswordAuth(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/converter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/converter.kt
index 1a4c1ee51ce4fc0cb8a721c0752cc165eba2c2c5..80630bc4e7fbf7eafa3015b21bae6b07a6e8a955 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/converter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/converter.kt
@@ -1,127 +1,129 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.api.auth
-
-import org.matrix.android.sdk.api.auth.data.LocalizedFlowDataLoginTerms
-import org.matrix.android.sdk.api.auth.registration.TermPolicies
-
-/**
- * This method extract the policies from the login terms parameter, regarding the user language.
- * For each policy, if user language is not found, the default language is used and if not found, the first url and name are used (not predictable)
- *
- * Example of Data:
- * <pre>
- * "m.login.terms": {
- *       "policies": {
- *         "privacy_policy": {
- *           "version": "1.0",
- *           "en": {
- *             "url": "http:\/\/matrix.org\/_matrix\/consent?v=1.0",
- *             "name": "Terms and Conditions"
- *           }
- *         }
- *       }
- *     }
- *</pre>
- *
- * @param userLanguage the user language
- * @param defaultLanguage the default language to use if the user language is not found for a policy in registrationFlowResponse
- */
-fun TermPolicies.toLocalizedLoginTerms(userLanguage: String,
-                                       defaultLanguage: String = "en"): List<LocalizedFlowDataLoginTerms> {
-    val result = ArrayList<LocalizedFlowDataLoginTerms>()
-
-    val policies = get("policies")
-    if (policies is Map<*, *>) {
-        policies.keys.forEach { policyName ->
-            val localizedFlowDataLoginTermsPolicyName = policyName as String
-            var localizedFlowDataLoginTermsVersion: String? = null
-            var localizedFlowDataLoginTermsLocalizedUrl: String? = null
-            var localizedFlowDataLoginTermsLocalizedName: String? = null
-
-            val policy = policies[policyName]
-
-            // Enter this policy
-            if (policy is Map<*, *>) {
-                // Version
-                localizedFlowDataLoginTermsVersion = policy["version"] as String?
-
-                var userLanguageUrlAndName: UrlAndName? = null
-                var defaultLanguageUrlAndName: UrlAndName? = null
-                var firstUrlAndName: UrlAndName? = null
-
-                // Search for language
-                policy.keys.forEach { policyKey ->
-                    when (policyKey) {
-                        "version"       -> Unit // Ignore
-                        userLanguage    -> {
-                            // We found the data for the user language
-                            userLanguageUrlAndName = extractUrlAndName(policy[policyKey])
-                        }
-                        defaultLanguage -> {
-                            // We found default language
-                            defaultLanguageUrlAndName = extractUrlAndName(policy[policyKey])
-                        }
-                        else            -> {
-                            if (firstUrlAndName == null) {
-                                // Get at least some data
-                                firstUrlAndName = extractUrlAndName(policy[policyKey])
-                            }
-                        }
-                    }
-                }
-
-                // Copy found language data by priority
-                when {
-                    userLanguageUrlAndName != null    -> {
-                        localizedFlowDataLoginTermsLocalizedUrl = userLanguageUrlAndName!!.url
-                        localizedFlowDataLoginTermsLocalizedName = userLanguageUrlAndName!!.name
-                    }
-                    defaultLanguageUrlAndName != null -> {
-                        localizedFlowDataLoginTermsLocalizedUrl = defaultLanguageUrlAndName!!.url
-                        localizedFlowDataLoginTermsLocalizedName = defaultLanguageUrlAndName!!.name
-                    }
-                    firstUrlAndName != null           -> {
-                        localizedFlowDataLoginTermsLocalizedUrl = firstUrlAndName!!.url
-                        localizedFlowDataLoginTermsLocalizedName = firstUrlAndName!!.name
-                    }
-                }
-            }
-
-            result.add(LocalizedFlowDataLoginTerms(
-                    policyName = localizedFlowDataLoginTermsPolicyName,
-                    version = localizedFlowDataLoginTermsVersion,
-                    localizedUrl = localizedFlowDataLoginTermsLocalizedUrl,
-                    localizedName = localizedFlowDataLoginTermsLocalizedName
-            ))
-        }
-    }
-
-    return result
-}
-
-private fun extractUrlAndName(policyData: Any?): UrlAndName? {
-    if (policyData is Map<*, *>) {
-        val url = policyData["url"] as String?
-        val name = policyData["name"] as String?
-
-        if (url != null && name != null) {
-            return UrlAndName(url, name)
-        }
-    }
-    return null
-}
+/*
+ * Copyright 2020 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.api.auth
+
+import org.matrix.android.sdk.api.auth.data.LocalizedFlowDataLoginTerms
+import org.matrix.android.sdk.api.auth.registration.TermPolicies
+
+/**
+ * This method extract the policies from the login terms parameter, regarding the user language.
+ * For each policy, if user language is not found, the default language is used and if not found, the first url and name are used (not predictable)
+ *
+ * Example of Data:
+ * <pre>
+ * "m.login.terms": {
+ *       "policies": {
+ *         "privacy_policy": {
+ *           "version": "1.0",
+ *           "en": {
+ *             "url": "http:\/\/matrix.org\/_matrix\/consent?v=1.0",
+ *             "name": "Terms and Conditions"
+ *           }
+ *         }
+ *       }
+ *     }
+ *</pre>
+ *
+ * @param userLanguage the user language
+ * @param defaultLanguage the default language to use if the user language is not found for a policy in registrationFlowResponse
+ */
+fun TermPolicies.toLocalizedLoginTerms(userLanguage: String,
+                                       defaultLanguage: String = "en"): List<LocalizedFlowDataLoginTerms> {
+    val result = ArrayList<LocalizedFlowDataLoginTerms>()
+
+    val policies = get("policies")
+    if (policies is Map<*, *>) {
+        policies.keys.forEach { policyName ->
+            val localizedFlowDataLoginTermsPolicyName = policyName as String
+            var localizedFlowDataLoginTermsVersion: String? = null
+            var localizedFlowDataLoginTermsLocalizedUrl: String? = null
+            var localizedFlowDataLoginTermsLocalizedName: String? = null
+
+            val policy = policies[policyName]
+
+            // Enter this policy
+            if (policy is Map<*, *>) {
+                // Version
+                localizedFlowDataLoginTermsVersion = policy["version"] as String?
+
+                var userLanguageUrlAndName: UrlAndName? = null
+                var defaultLanguageUrlAndName: UrlAndName? = null
+                var firstUrlAndName: UrlAndName? = null
+
+                // Search for language
+                policy.keys.forEach { policyKey ->
+                    when (policyKey) {
+                        "version"       -> Unit // Ignore
+                        userLanguage    -> {
+                            // We found the data for the user language
+                            userLanguageUrlAndName = extractUrlAndName(policy[policyKey])
+                        }
+                        defaultLanguage -> {
+                            // We found default language
+                            defaultLanguageUrlAndName = extractUrlAndName(policy[policyKey])
+                        }
+                        else            -> {
+                            if (firstUrlAndName == null) {
+                                // Get at least some data
+                                firstUrlAndName = extractUrlAndName(policy[policyKey])
+                            }
+                        }
+                    }
+                }
+
+                // Copy found language data by priority
+                when {
+                    userLanguageUrlAndName != null    -> {
+                        localizedFlowDataLoginTermsLocalizedUrl = userLanguageUrlAndName!!.url
+                        localizedFlowDataLoginTermsLocalizedName = userLanguageUrlAndName!!.name
+                    }
+                    defaultLanguageUrlAndName != null -> {
+                        localizedFlowDataLoginTermsLocalizedUrl = defaultLanguageUrlAndName!!.url
+                        localizedFlowDataLoginTermsLocalizedName = defaultLanguageUrlAndName!!.name
+                    }
+                    firstUrlAndName != null           -> {
+                        localizedFlowDataLoginTermsLocalizedUrl = firstUrlAndName!!.url
+                        localizedFlowDataLoginTermsLocalizedName = firstUrlAndName!!.name
+                    }
+                }
+            }
+
+            result.add(
+                    LocalizedFlowDataLoginTerms(
+                            policyName = localizedFlowDataLoginTermsPolicyName,
+                            version = localizedFlowDataLoginTermsVersion,
+                            localizedUrl = localizedFlowDataLoginTermsLocalizedUrl,
+                            localizedName = localizedFlowDataLoginTermsLocalizedName
+                    )
+            )
+        }
+    }
+
+    return result
+}
+
+private fun extractUrlAndName(policyData: Any?): UrlAndName? {
+    if (policyData is Map<*, *>) {
+        val url = policyData["url"] as String?
+        val name = policyData["name"] as String?
+
+        if (url != null && name != null) {
+            return UrlAndName(url, name)
+        }
+    }
+    return null
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/Credentials.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/Credentials.kt
index 317acccfb513cbfa77e04b8e87731e8c2c9f8ad4..e3728753adc6d9cea7003861ff88d6068bed0d7b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/Credentials.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/Credentials.kt
@@ -37,7 +37,7 @@ data class Credentials(
          */
         @Json(name = "access_token") val accessToken: String,
         /**
-         * Not documented
+         * Not documented.
          */
         @Json(name = "refresh_token") val refreshToken: String?,
         /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt
index b490ac877ee4e455532d5566631f7753b169fa51..e3815231d93dd04d2ac4f8422d90976fc07d54c7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SessionParams.kt
@@ -22,12 +22,12 @@ package org.matrix.android.sdk.api.auth.data
  */
 data class SessionParams(
         /**
-         * Please consider using shortcuts instead
+         * Please consider using shortcuts instead.
          */
         val credentials: Credentials,
 
         /**
-         * Please consider using shortcuts instead
+         * Please consider using shortcuts instead.
          */
         val homeServerConnectionConfig: HomeServerConnectionConfig,
 
@@ -41,12 +41,12 @@ data class SessionParams(
      */
 
     /**
-     * The userId of the session (Ex: "@user:domain.org")
+     * The userId of the session (Ex: "@user:domain.org").
      */
     val userId = credentials.userId
 
     /**
-     * The deviceId of the session (Ex: "ABCDEFGH")
+     * The deviceId of the session (Ex: "ABCDEFGH").
      */
     val deviceId = credentials.deviceId
 
@@ -62,12 +62,12 @@ data class SessionParams(
     val homeServerUrlBase = homeServerConnectionConfig.homeServerUriBase.toString()
 
     /**
-     * The current homeserver host, using what has been entered by the user during login phase
+     * The current homeserver host, using what has been entered by the user during login phase.
      */
     val homeServerHost = homeServerConnectionConfig.homeServerUri.host
 
     /**
-     * The default identity server url if any, returned by the homeserver during login phase
+     * The default identity server url if any, returned by the homeserver during login phase.
      */
     val defaultIdentityServerUrl = homeServerConnectionConfig.identityServerUri?.toString()
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/WellKnown.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/WellKnown.kt
index 4bcef606051672ec7e377a1b925153ff042951f1..10c7d513923b53c37ed47397957b8d288aaa3089 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/WellKnown.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/WellKnown.kt
@@ -43,6 +43,7 @@ import org.matrix.android.sdk.api.util.JsonDict
  *    }
  * }
  * </pre>
+ * .
  */
 @JsonClass(generateAdapter = true)
 data class WellKnown(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/WellKnownBaseConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/WellKnownBaseConfig.kt
index ad6b9970de4c3de4bc79d9fa6c2f3b001ab1f475..df0009923219c57ee51d9f3cbacbb6487f6c79ff 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/WellKnownBaseConfig.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/WellKnownBaseConfig.kt
@@ -26,6 +26,7 @@ import com.squareup.moshi.JsonClass
  *     "base_url": "https://vector.im"
  * }
  * </pre>
+ * .
  */
 @JsonClass(generateAdapter = true)
 data class WellKnownBaseConfig(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt
index 247d58ce7972bcd2157478726d2747cdcfbd8420..3232025de39a0c3c2271a7dbc34ed66e8466309a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt
@@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.util.JsonDict
  */
 interface LoginWizard {
     /**
-     * Get some information about a matrixId: displayName and avatar url
+     * Get some information about a matrixId: displayName and avatar url.
      */
     suspend fun getProfileInfo(matrixId: String): LoginProfileInfo
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt
index 0da9eb4b7e157dc984fc5ad159b23ed08662d2c2..1252e93b84848d72b678977b269e37a73b603b9e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt
@@ -73,7 +73,7 @@ data class RegistrationFlowResponse(
 )
 
 /**
- * Convert to something easier to handle on client side
+ * Convert to something easier to handle on client side.
  */
 fun RegistrationFlowResponse.toFlowResult(): FlowResult {
     // Get all the returned stages
@@ -88,8 +88,10 @@ fun RegistrationFlowResponse.toFlowResult(): FlowResult {
         val isMandatory = flows?.all { type in it.stages.orEmpty() } == true
 
         val stage = when (type) {
-            LoginFlowTypes.RECAPTCHA      -> Stage.ReCaptcha(isMandatory, ((params?.get(type) as? Map<*, *>)?.get("public_key") as? String)
-                    ?: "")
+            LoginFlowTypes.RECAPTCHA      -> Stage.ReCaptcha(
+                    isMandatory, ((params?.get(type) as? Map<*, *>)?.get("public_key") as? String)
+                    ?: ""
+            )
             LoginFlowTypes.DUMMY          -> Stage.Dummy(isMandatory)
             LoginFlowTypes.TERMS          -> Stage.Terms(isMandatory, params?.get(type) as? TermPolicies ?: emptyMap<String, String>())
             LoginFlowTypes.EMAIL_IDENTITY -> Stage.Email(isMandatory)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/CryptoConstants.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/CryptoConstants.kt
index 172cfa8360752d6a150a4e96be8d781ec047f837..37b9ac379e285f9814f675d72b8525f40c92cd78 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/CryptoConstants.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/CryptoConstants.kt
@@ -32,7 +32,7 @@ const val MXCRYPTO_ALGORITHM_MEGOLM = "m.megolm.v1.aes-sha2"
 const val MXCRYPTO_ALGORITHM_MEGOLM_BACKUP = "m.megolm_backup.v1.curve25519-aes-sha2"
 
 /**
- * Secured Shared Storage algorithm constant
+ * Secured Shared Storage algorithm constant.
  */
 const val SSSS_ALGORITHM_CURVE25519_AES_SHA2 = "m.secret_storage.v1.curve25519-aes-sha2"
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/Emojis.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/Emojis.kt
index 9c0eb10970a2e4109d7a22c59bf11bad1a2eaccc..85d6961384fcf0378580f4fadbd3588e7beb9904 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/Emojis.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/Emojis.kt
@@ -20,7 +20,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentatio
 import org.matrix.android.sdk.internal.crypto.verification.getEmojiForCode
 
 /**
- * Provide all the emojis used for SAS verification (for debug purpose)
+ * Provide all the emojis used for SAS verification (for debug purpose).
  */
 fun getAllVerificationEmojis(): List<EmojiRepresentation> {
     return (0..63).map { getEmojiForCode(it) }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/MXCryptoConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/MXCryptoConfig.kt
index 9a686de2e123ac35617d782627968c41400dcf8a..9507ddda65726c55a513db0bbd707b224389e242 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/MXCryptoConfig.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/MXCryptoConfig.kt
@@ -31,5 +31,11 @@ data class MXCryptoConfig constructor(
          * If set to false, the request will be forwarded to the application layer; in this
          * case the application can decide to prompt the user.
          */
-        val discardRoomKeyRequestsFromUntrustedDevices: Boolean = true
+        val discardRoomKeyRequestsFromUntrustedDevices: Boolean = true,
+
+        /**
+         * Currently megolm keys are requested to the sender device and to all of our devices.
+         * You can limit request only to your sessions by turning this setting to `true`
+         */
+        val limitRoomKeyRequestsToMyDevices: Boolean = false,
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/extensions/Strings.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/extensions/Strings.kt
index e264843ea49654ce151cb29b5529a12e69db8113..5e1350e32791ac60019659e3356511fc3b353708 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/extensions/Strings.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/extensions/Strings.kt
@@ -24,6 +24,6 @@ fun CharSequence.ensurePrefix(prefix: CharSequence): CharSequence {
 }
 
 /**
- * Append a new line and then the provided string
+ * Append a new line and then the provided string.
  */
 fun StringBuilder.appendNl(str: String) = append("\n").append(str)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
index 362ebcec26db18b2f0829fd215685ba90f9c66e2..d3cc8fc8e48a94a394bebac28f15598a830edd5e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
@@ -47,7 +47,7 @@ fun Throwable.shouldBeRetried() = this is Failure.NetworkConnection ||
         isLimitExceededError()
 
 /**
- * Get the retry delay in case of rate limit exceeded error, adding 100 ms, of defaultValue otherwise
+ * Get the retry delay in case of rate limit exceeded error, adding 100 ms, of defaultValue otherwise.
  */
 fun Throwable.getRetryDelay(defaultValue: Long): Long {
     return (this as? Failure.ServerError)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/InitialSyncRequestReason.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/InitialSyncRequestReason.kt
index ebe07823f470f3fbdca55586dcb49e2787742b06..8bebbcc3a5d3bb51ba36de59aaba0b51dc464f82 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/InitialSyncRequestReason.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/InitialSyncRequestReason.kt
@@ -17,11 +17,11 @@
 package org.matrix.android.sdk.api.failure
 
 /**
- * This enum provide the reason why the SDK request an initial sync to the application
+ * This enum provide the reason why the SDK request an initial sync to the application.
  */
 enum class InitialSyncRequestReason {
     /**
-     * The list of ignored users has changed, and at least one user who was ignored is not ignored anymore
+     * The list of ignored users has changed, and at least one user who was ignored is not ignored anymore.
      */
     IGNORED_USERS_LIST_CHANGE,
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt
index 32e1aca17d83efdc7bea4d21c84204d0e16c6e6e..3dbbc3956436af4a38985783f682fe7115558c2f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/MatrixError.kt
@@ -28,9 +28,9 @@ import org.matrix.android.sdk.api.util.JsonDict
  */
 @JsonClass(generateAdapter = true)
 data class MatrixError(
-        /** unique string which can be used to handle an error message */
+        /** unique string which can be used to handle an error message. */
         @Json(name = "errcode") val code: String,
-        /** human-readable error message */
+        /** human-readable error message. */
         @Json(name = "error") val message: String,
 
         // For M_CONSENT_NOT_GIVEN
@@ -92,19 +92,19 @@ data class MatrixError(
         /** Sent when the room alias given to the createRoom API is already in use. */
         const val M_ROOM_IN_USE = "M_ROOM_IN_USE"
 
-        /** (Not documented yet) */
+        /** (Not documented yet). */
         const val M_BAD_PAGINATION = "M_BAD_PAGINATION"
 
         /** The request was not correctly authorized. Usually due to login failures. */
         const val M_UNAUTHORIZED = "M_UNAUTHORIZED"
 
-        /** (Not documented yet) */
+        /** (Not documented yet). */
         const val M_OLD_VERSION = "M_OLD_VERSION"
 
         /** The server did not understand the request. */
         const val M_UNRECOGNIZED = "M_UNRECOGNIZED"
 
-        /** (Not documented yet) */
+        /** (Not documented yet). */
         const val M_LOGIN_EMAIL_URL_NOT_YET = "M_LOGIN_EMAIL_URL_NOT_YET"
 
         /** Authentication could not be performed on the third party identifier. */
@@ -122,7 +122,7 @@ data class MatrixError(
         /** The request or entity was too large. */
         const val M_TOO_LARGE = "M_TOO_LARGE"
 
-        /** (Not documented yet) */
+        /** (Not documented yet). */
         const val M_CONSENT_NOT_GIVEN = "M_CONSENT_NOT_GIVEN"
 
         /** The request cannot be completed because the homeserver has reached a resource limit imposed on it. For example,
@@ -176,10 +176,10 @@ data class MatrixError(
         /** The user is unable to reject an invite to join the server notices room. See the Server Notices module for more information. */
         const val M_CANNOT_LEAVE_SERVER_NOTICE_ROOM = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM"
 
-        /** (Not documented yet) */
+        /** (Not documented yet). */
         const val M_WRONG_ROOM_KEYS_VERSION = "M_WRONG_ROOM_KEYS_VERSION"
 
-        /** (Not documented yet) */
+        /** (Not documented yet). */
         const val M_WEAK_PASSWORD = "M_WEAK_PASSWORD"
 
         /** The provided password's length is shorter than the minimum length required by the server. */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/federation/FederationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/federation/FederationService.kt
index 0761ef8d21a6fb731ceb2d1fe1acf0b72078429e..8fe646075346bf645e7ebf3e595a052f94a8aa14 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/federation/FederationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/federation/FederationService.kt
@@ -18,7 +18,7 @@ package org.matrix.android.sdk.api.federation
 
 interface FederationService {
     /**
-     * Get information about the homeserver
+     * Get information about the homeserver.
      */
     suspend fun getFederationVersion(): FederationVersion
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/listeners/ProgressListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/listeners/ProgressListener.kt
index 02ebd7f784ae17c51b1609f7d73ebdef9506d706..ec55348dc5abbc4bb0d87cd9be33413ff9f2fb99 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/listeners/ProgressListener.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/listeners/ProgressListener.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.api.listeners
 
 /**
- * Interface to send a progress info
+ * Interface to send a progress info.
  */
 interface ProgressListener {
     /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/listeners/StepProgressListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/listeners/StepProgressListener.kt
index 0fabfed2ff393ab50f2e8adf33feb6e29957f0a7..4b87507c02e5084387fd37119d160f7d73a60a27 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/listeners/StepProgressListener.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/listeners/StepProgressListener.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.api.listeners
 
 /**
- * Interface to send a progress info
+ * Interface to send a progress info.
  */
 interface StepProgressListener {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt
index 44ac439d7b04fc95ba3ec168ad4c210c737b75c7..ae65963f37b26c3ccf654d3bf1ca8ea29998b792 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt
@@ -22,15 +22,15 @@ package org.matrix.android.sdk.api.logger
  * val loggerTag = LoggerTag("MyTag", LoggerTag.VOIP)
  * Timber.tag(loggerTag.value).v("My log message")
  */
-open class LoggerTag(_value: String, parentTag: LoggerTag? = null) {
+open class LoggerTag(name: String, parentTag: LoggerTag? = null) {
 
     object SYNC : LoggerTag("SYNC")
     object VOIP : LoggerTag("VOIP")
     object CRYPTO : LoggerTag("CRYPTO")
 
     val value: String = if (parentTag == null) {
-        _value
+        name
     } else {
-        "${parentTag.value}/$_value"
+        "${parentTag.value}/$name"
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt
index 31ec131c5ca9558710acf93335b196404776425e..368ff986613783037cd0b44771d9d8ebdfb9fdcd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt
@@ -36,19 +36,19 @@ sealed interface QueryStringValue {
 
     enum class Case {
         /**
-         * Match query sensitive to case
+         * Match query sensitive to case.
          */
         SENSITIVE,
 
         /**
-         * Match query insensitive to case, this only works for Latin-1 character sets
+         * Match query insensitive to case, this only works for Latin-1 character sets.
          */
         INSENSITIVE,
 
         /**
-         * Match query with input normalized (case insensitive)
-         * Works around Realms inability to sort or filter by case for non Latin-1 character sets
-         * Expects the target field to contain normalized data
+         * Match query with input normalized (case insensitive).
+         * Works around Realms inability to sort or filter by case for non Latin-1 character sets.
+         * Expects the target field to contain normalized data.
          *
          * @see org.matrix.android.sdk.internal.util.Normalizer.normalize
          */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt
index 3366d040f7fa1227a6b72cc9668fa411681fea88..71a4f84a8da05a4f27ee17b43ff0bda4b9ed5018 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt
@@ -23,19 +23,19 @@ import org.matrix.android.sdk.api.cache.CacheStrategy
  */
 interface RawService {
     /**
-     * Get a URL, either from cache or from the remote server, depending on the cache strategy
+     * Get a URL, either from cache or from the remote server, depending on the cache strategy.
      */
     suspend fun getUrl(url: String, cacheStrategy: CacheStrategy): String
 
     /**
-     * Specific case for the well-known file. Cache validity is 8 hours
+     * Specific case for the well-known file. Cache validity is 8 hours.
      * @param domain the domain to get the .well-known file, for instance "matrix.org".
      * The URL will be "https://{domain}/.well-known/matrix/client"
      */
     suspend fun getWellknown(domain: String): String
 
     /**
-     * Clear all the cache data
+     * Clear all the cache data.
      */
     suspend fun clearCache()
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
index 19502f0b46b873a1d658aad6986bbb53f9cce91c..2f1ae8cd87626fe744434bdecd911d40c5118312 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt
@@ -72,23 +72,23 @@ interface Session {
     val coroutineDispatchers: MatrixCoroutineDispatchers
 
     /**
-     * The params associated to the session
+     * The params associated to the session.
      */
     val sessionParams: SessionParams
 
     /**
-     * The session is valid, i.e. it has a valid token so far
+     * The session is valid, i.e. it has a valid token so far.
      */
     val isOpenable: Boolean
 
     /**
-     * Useful shortcut to get access to the userId
+     * Useful shortcut to get access to the userId.
      */
     val myUserId: String
         get() = sessionParams.userId
 
     /**
-     * The sessionId
+     * The sessionId.
      */
     val sessionId: String
 
@@ -99,16 +99,16 @@ interface Session {
     fun open()
 
     /**
-     * Requires a one time background sync
+     * Requires a one time background sync.
      */
     fun requireBackgroundSync()
 
     /**
-     * Launches infinite self rescheduling background syncs via the WorkManager
+     * Launches infinite self rescheduling background syncs via the WorkManager.
      *
-     * While dozing, syncs will only occur during maintenance windows
+     * While dozing, syncs will only occur during maintenance windows.
      * For reliability it's recommended to also start a long running foreground service
-     * along with disabling battery optimizations
+     * along with disabling battery optimizations.
      */
     fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long)
 
@@ -125,7 +125,7 @@ interface Session {
     fun stopSync()
 
     /**
-     * Clear cache of the session
+     * Clear cache of the session.
      */
     suspend fun clearCache()
 
@@ -147,7 +147,7 @@ interface Session {
     fun syncFlow(): SharedFlow<SyncResponse>
 
     /**
-     * This methods return true if an initial sync has been processed
+     * This methods return true if an initial sync has been processed.
      */
     fun hasAlreadySynced(): Boolean
 
@@ -162,187 +162,187 @@ interface Session {
     fun contentUrlResolver(): ContentUrlResolver
 
     /**
-     * Returns the ContentUploadProgressTracker associated with the session
+     * Returns the ContentUploadProgressTracker associated with the session.
      */
     fun contentUploadProgressTracker(): ContentUploadStateTracker
 
     /**
-     * Returns the TypingUsersTracker associated with the session
+     * Returns the TypingUsersTracker associated with the session.
      */
     fun typingUsersTracker(): TypingUsersTracker
 
     /**
-     * Returns the ContentDownloadStateTracker associated with the session
+     * Returns the ContentDownloadStateTracker associated with the session.
      */
     fun contentDownloadProgressTracker(): ContentDownloadStateTracker
 
     /**
-     * Returns the cryptoService associated with the session
+     * Returns the cryptoService associated with the session.
      */
     fun cryptoService(): CryptoService
 
     /**
-     * Returns the ContentScannerService associated with the session
+     * Returns the ContentScannerService associated with the session.
      */
     fun contentScannerService(): ContentScannerService
 
     /**
-     * Returns the identity service associated with the session
+     * Returns the identity service associated with the session.
      */
     fun identityService(): IdentityService
 
     /**
-     * Returns the HomeServerCapabilities service associated with the session
+     * Returns the HomeServerCapabilities service associated with the session.
      */
     fun homeServerCapabilitiesService(): HomeServerCapabilitiesService
 
     /**
-     * Returns the RoomService associated with the session
+     * Returns the RoomService associated with the session.
      */
     fun roomService(): RoomService
 
     /**
-     * Returns the RoomDirectoryService associated with the session
+     * Returns the RoomDirectoryService associated with the session.
      */
     fun roomDirectoryService(): RoomDirectoryService
 
     /**
-     * Returns the GroupService associated with the session
+     * Returns the GroupService associated with the session.
      */
     fun groupService(): GroupService
 
     /**
-     * Returns the UserService associated with the session
+     * Returns the UserService associated with the session.
      */
     fun userService(): UserService
 
     /**
-     * Returns the SignOutService associated with the session
+     * Returns the SignOutService associated with the session.
      */
     fun signOutService(): SignOutService
 
     /**
-     * Returns the FilterService associated with the session
+     * Returns the FilterService associated with the session.
      */
     fun filterService(): FilterService
 
     /**
-     * Returns the PushRuleService associated with the session
+     * Returns the PushRuleService associated with the session.
      */
     fun pushRuleService(): PushRuleService
 
     /**
-     * Returns the PushersService associated with the session
+     * Returns the PushersService associated with the session.
      */
     fun pushersService(): PushersService
 
     /**
-     * Returns the EventService associated with the session
+     * Returns the EventService associated with the session.
      */
     fun eventService(): EventService
 
     /**
-     * Returns the TermsService associated with the session
+     * Returns the TermsService associated with the session.
      */
     fun termsService(): TermsService
 
     /**
-     * Returns the SyncStatusService associated with the session
+     * Returns the SyncStatusService associated with the session.
      */
     fun syncStatusService(): SyncStatusService
 
     /**
-     * Returns the SecureStorageService associated with the session
+     * Returns the SecureStorageService associated with the session.
      */
     fun secureStorageService(): SecureStorageService
 
     /**
-     * Returns the ProfileService associated with the session
+     * Returns the ProfileService associated with the session.
      */
     fun profileService(): ProfileService
 
     /**
-     * Returns the PresenceService associated with the session
+     * Returns the PresenceService associated with the session.
      */
     fun presenceService(): PresenceService
 
     /**
-     * Returns the AccountService associated with the session
+     * Returns the AccountService associated with the session.
      */
     fun accountService(): AccountService
 
     /**
-     * Returns the ToDeviceService associated with the session
+     * Returns the ToDeviceService associated with the session.
      */
     fun toDeviceService(): ToDeviceService
 
     /**
-     * Returns the EventStreamService associated with the session
+     * Returns the EventStreamService associated with the session.
      */
     fun eventStreamService(): EventStreamService
 
     /**
-     * Returns the widget service associated with the session
+     * Returns the widget service associated with the session.
      */
     fun widgetService(): WidgetService
 
     /**
-     * Returns the media service associated with the session
+     * Returns the media service associated with the session.
      */
     fun mediaService(): MediaService
 
     /**
-     * Returns the integration manager service associated with the session
+     * Returns the integration manager service associated with the session.
      */
     fun integrationManagerService(): IntegrationManagerService
 
     /**
-     * Returns the call signaling service associated with the session
+     * Returns the call signaling service associated with the session.
      */
     fun callSignalingService(): CallSignalingService
 
     /**
-     * Returns the file download service associated with the session
+     * Returns the file download service associated with the session.
      */
     fun fileService(): FileService
 
     /**
-     * Returns the permalink service associated with the session
+     * Returns the permalink service associated with the session.
      */
     fun permalinkService(): PermalinkService
 
     /**
-     * Returns the search service associated with the session
+     * Returns the search service associated with the session.
      */
     fun searchService(): SearchService
 
     /**
-     * Returns the federation service associated with the session
+     * Returns the federation service associated with the session.
      */
     fun federationService(): FederationService
 
     /**
-     * Returns the third party service associated with the session
+     * Returns the third party service associated with the session.
      */
     fun thirdPartyService(): ThirdPartyService
 
     /**
-     * Returns the space service associated with the session
+     * Returns the space service associated with the session.
      */
     fun spaceService(): SpaceService
 
     /**
-     * Returns the open id service associated with the session
+     * Returns the open id service associated with the session.
      */
     fun openIdService(): OpenIdService
 
     /**
-     * Returns the account data service associated with the session
+     * Returns the account data service associated with the session.
      */
     fun accountDataService(): SessionAccountDataService
 
     /**
-     * Returns the SharedSecretStorageService associated with the session
+     * Returns the SharedSecretStorageService associated with the session.
      */
     fun sharedSecretStorageService(): SharedSecretStorageService
 
@@ -377,8 +377,8 @@ interface Session {
         /**
          * Possible cases:
          * - The access token is not valid anymore,
-         * - a M_CONSENT_NOT_GIVEN error has been received from the homeserver
-         * See [GlobalError] for all the possible cases
+         * - a M_CONSENT_NOT_GIVEN error has been received from the homeserver;
+         * See [GlobalError] for all the possible cases.
          */
         fun onGlobalError(session: Session, globalError: GlobalError) = Unit
     }
@@ -386,7 +386,7 @@ interface Session {
     fun getUiaSsoFallbackUrl(authenticationSessionId: String): String
 
     /**
-     * Maintenance API, allows to print outs info on DB size to logcat
+     * Maintenance API, allows to print outs info on DB size to logcat.
      */
     fun logDbUsageInfo()
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/SessionExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/SessionExtensions.kt
index aeb0e7e4ee73f5dee19e8e7cccb1ad16b1b4aa9a..a15e73eb88f007dd917797478d1c6c9896641f6c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/SessionExtensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/SessionExtensions.kt
@@ -21,16 +21,16 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.api.session.user.model.User
 
 /**
- * Get a room using the RoomService of a Session
+ * Get a room using the RoomService of a Session.
  */
 fun Session.getRoom(roomId: String): Room? = roomService().getRoom(roomId)
 
 /**
- * Get a room summary using the RoomService of a Session
+ * Get a room summary using the RoomService of a Session.
  */
 fun Session.getRoomSummary(roomIdOrAlias: String): RoomSummary? = roomService().getRoomSummary(roomIdOrAlias)
 
 /**
- * Get a user using the UserService of a Session
+ * Get a user using the UserService of a Session.
  */
 fun Session.getUser(userId: String): User? = userService().getUser(userId)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/ToDeviceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/ToDeviceService.kt
index d7afad5b6c4ecd33f49201bc44e9973cabb725cc..56e5ebdbe7e3f5faa756d5bc3506712c7732bf3e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/ToDeviceService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/ToDeviceService.kt
@@ -21,9 +21,8 @@ import org.matrix.android.sdk.api.session.events.model.Content
 import java.util.UUID
 
 interface ToDeviceService {
-
     /**
-     * Send an event to a specific list of devices
+     * Send an event to a specific list of devices.
      */
     suspend fun sendToDevice(eventType: String, contentMap: MXUsersDevicesMap<Any>, txnId: String? = UUID.randomUUID().toString())
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/SessionAccountDataService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/SessionAccountDataService.kt
index 2ffb9112d1e8ee56bfaab92a491643bf8c15b96e..a22dd3377454036d620289e84f8e8cca52126b53 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/SessionAccountDataService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/accountdata/SessionAccountDataService.kt
@@ -26,12 +26,12 @@ import org.matrix.android.sdk.api.util.Optional
  */
 interface SessionAccountDataService {
     /**
-     * Retrieve the account data with the provided type or null if not found
+     * Retrieve the account data with the provided type or null if not found.
      */
     fun getUserAccountDataEvent(type: String): UserAccountDataEvent?
 
     /**
-     * Observe the account data with the provided type
+     * Observe the account data with the provided type.
      */
     fun getLiveUserAccountDataEvent(type: String): LiveData<Optional<UserAccountDataEvent>>
 
@@ -60,7 +60,7 @@ interface SessionAccountDataService {
     fun getLiveRoomAccountDataEvents(types: Set<String>): LiveData<List<RoomAccountDataEvent>>
 
     /**
-     * Update the account data with the provided type and the provided account data content
+     * Update the account data with the provided type and the provided account data content.
      */
     suspend fun updateUserAccountData(type: String, content: Content)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallListener.kt
index d17be59cd4d4cd5556b59b94dd7718dc1771b530..7f932e881532f1b1e0ab68dbfed9b5bd0c568278 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallListener.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallListener.kt
@@ -39,32 +39,32 @@ interface CallListener {
     fun onCallAnswerReceived(callAnswerContent: CallAnswerContent)
 
     /**
-     * Called when a called has been hung up
+     * Called when a called has been hung up.
      */
     fun onCallHangupReceived(callHangupContent: CallHangupContent)
 
     /**
-     * Called when a called has been rejected
+     * Called when a called has been rejected.
      */
     fun onCallRejectReceived(callRejectContent: CallRejectContent)
 
     /**
-     * Called when an answer has been selected
+     * Called when an answer has been selected.
      */
     fun onCallSelectAnswerReceived(callSelectAnswerContent: CallSelectAnswerContent)
 
     /**
-     * Called when a negotiation is sent
+     * Called when a negotiation is sent.
      */
     fun onCallNegotiateReceived(callNegotiateContent: CallNegotiateContent)
 
     /**
-     * Called when the call has been managed by an other session
+     * Called when the call has been managed by an other session.
      */
     fun onCallManagedByOtherSession(callId: String)
 
     /**
-     * Called when an asserted identity event is received
+     * Called when an asserted identity event is received.
      */
     fun onCallAssertedIdentityReceived(callAssertedIdentityContent: CallAssertedIdentityContent)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt
index c34744e75f5f7ef13a6fa8edb68349897a36c309..e17c02c40aed9032c969132ff6ceca835fdf912d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt
@@ -21,7 +21,7 @@ interface CallSignalingService {
     suspend fun getTurnServer(): TurnServerResponse
 
     /**
-     * Create an outgoing call
+     * Create an outgoing call.
      */
     fun createOutgoingCall(roomId: String, otherUserId: String, isVideoCall: Boolean): MxCall
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt
index ff1df63300c36f775b5731c6eaa74ae4183ef2c8..4bf78c9d6aa65cd3ecbd42d1e3b4206ebc64c66b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt
@@ -20,7 +20,7 @@ import org.matrix.android.sdk.api.session.room.model.call.EndCallReason
 
 sealed class CallState {
 
-    /** Idle, setting up objects */
+    /** Idle, setting up objects. */
     object Idle : CallState()
 
     /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt
index dd23e81cc6a062697aa29bf1322727b6e6ed2697..e13f7310e05696cecfa81c396f8357a5266d67ec 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt
@@ -35,7 +35,7 @@ interface MxCallDetail {
 }
 
 /**
- * Define both an incoming call and on outgoing call
+ * Define both an incoming call and on outgoing call.
  */
 interface MxCall : MxCallDetail {
 
@@ -46,13 +46,13 @@ interface MxCall : MxCallDetail {
     var state: CallState
 
     /**
-     * Pick Up the incoming call
-     * It has no effect on outgoing call
+     * Pick Up the incoming call.
+     * It has no effect on outgoing call.
      */
     fun accept(sdpString: String)
 
     /**
-     * SDP negotiation for media pause, hold/resume, ICE restarts and voice/video call up/downgrading
+     * SDP negotiation for media pause, hold/resume, ICE restarts and voice/video call up/downgrading.
      */
     fun negotiate(sdpString: String, type: SdpType)
 
@@ -62,17 +62,17 @@ interface MxCall : MxCallDetail {
     fun selectAnswer()
 
     /**
-     * Reject an incoming call
+     * Reject an incoming call.
      */
     fun reject()
 
     /**
-     * End the call
+     * End the call.
      */
     fun hangUp(reason: EndCallReason? = null)
 
     /**
-     * Start a call
+     * Start a call.
      * Send offer SDP to the other participant.
      */
     fun offerSdp(sdpString: String)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUrlResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUrlResolver.kt
index 523d60359b00309392c01c65fab5185049aa4185..e59e676ed9587f2670bbce0db540e7e5011a34ad 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUrlResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUrlResolver.kt
@@ -29,7 +29,7 @@ interface ContentUrlResolver {
     }
 
     /**
-     * URL to use to upload content
+     * URL to use to upload content.
      */
     val uploadUrl: String
 
@@ -42,7 +42,7 @@ interface ContentUrlResolver {
     fun resolveFullSize(contentUrl: String?): String?
 
     /**
-     * Get the ResolvedMethod to download a URL
+     * Get the ResolvedMethod to download a URL.
      *
      * @param contentUrl  the Matrix media content URI (in the form of "mxc://...").
      * @param elementToDecrypt Encryption data may be required if you use a content scanner
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
index d6d1248de78f01711a14f2599caccf968752115e..35f3ab3162466745fb6c09ec19e33368d392cbf6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
@@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningServic
 import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
 import org.matrix.android.sdk.api.session.crypto.keyshare.GossipingRequestListener
+import org.matrix.android.sdk.api.session.crypto.model.AuditTrail
 import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
 import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
 import org.matrix.android.sdk.api.session.crypto.model.DevicesListResponse
@@ -35,8 +36,6 @@ import org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo
 import org.matrix.android.sdk.api.session.crypto.model.MXEncryptEventContentResult
 import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult
 import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingRoomKeyRequest
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
 import org.matrix.android.sdk.api.session.events.model.Content
 import org.matrix.android.sdk.api.session.events.model.Event
@@ -76,6 +75,15 @@ interface CryptoService {
 
     fun setGlobalBlacklistUnverifiedDevices(block: Boolean)
 
+    /**
+     * Enable or disable key gossiping.
+     * Default is true.
+     * If set to false this device won't send key_request nor will accept key forwarded
+     */
+    fun enableKeyGossiping(enable: Boolean)
+
+    fun isKeyGossipingEnabled(): Boolean
+
     fun setRoomUnBlacklistUnverifiedDevices(roomId: String)
 
     fun getDeviceTrackingStatus(userId: String): Int
@@ -94,8 +102,6 @@ interface CryptoService {
 
     fun reRequestRoomKeyForEvent(event: Event)
 
-    fun cancelRoomKeyRequest(requestBody: RoomKeyRequestBody)
-
     fun addRoomKeysRequestListener(listener: GossipingRequestListener)
 
     fun removeRoomKeysRequestListener(listener: GossipingRequestListener)
@@ -142,14 +148,20 @@ interface CryptoService {
     fun addNewSessionListener(newSessionListener: NewSessionListener)
     fun removeSessionListener(listener: NewSessionListener)
 
-    fun getOutgoingRoomKeyRequests(): List<OutgoingRoomKeyRequest>
-    fun getOutgoingRoomKeyRequestsPaged(): LiveData<PagedList<OutgoingRoomKeyRequest>>
+    fun getOutgoingRoomKeyRequests(): List<OutgoingKeyRequest>
+    fun getOutgoingRoomKeyRequestsPaged(): LiveData<PagedList<OutgoingKeyRequest>>
 
     fun getIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest>
     fun getIncomingRoomKeyRequestsPaged(): LiveData<PagedList<IncomingRoomKeyRequest>>
 
-    fun getGossipingEventsTrail(): LiveData<PagedList<Event>>
-    fun getGossipingEvents(): List<Event>
+    /**
+     * Can be called by the app layer to accept a request manually.
+     * Use carefully as it is prone to social attacks.
+     */
+    suspend fun manuallyAcceptRoomKeyRequest(request: IncomingRoomKeyRequest)
+
+    fun getGossipingEventsTrail(): LiveData<PagedList<AuditTrail>>
+    fun getGossipingEvents(): List<AuditTrail>
 
     // For testing shared session
     fun getSharedWithInfo(roomId: String?, sessionId: String): MXUsersDevicesMap<Int>
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/MXCryptoError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/MXCryptoError.kt
index 5ff4b54b110907fe8e4eb1860ff7aaa2568b7524..0b5bbe3bbdb5f38e6fd818b5490e6b8850825b6d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/MXCryptoError.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/MXCryptoError.kt
@@ -28,7 +28,7 @@ sealed class MXCryptoError : Throwable() {
     data class Base(val errorType: ErrorType,
                     val technicalMessage: String,
                     /**
-                     * Describe the error with more details
+                     * Describe the error with more details.
                      */
                     val detailedErrorDescription: String? = null) : MXCryptoError()
 
@@ -63,7 +63,7 @@ sealed class MXCryptoError : Throwable() {
 
     companion object {
         /**
-         * Resource for technicalMessage
+         * Resource for technicalMessage.
          */
         const val UNABLE_TO_ENCRYPT_REASON = "Unable to encrypt %s"
         const val UNABLE_TO_DECRYPT_REASON = "Unable to decrypt %1\$s. Algorithm: %2\$s"
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/NewSessionListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/NewSessionListener.kt
index 73cbf5fb78a382d1c687985063e8850bbca951d2..d9e841a50ffe01461a2bef0f0fc4e400537540b0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/NewSessionListener.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/NewSessionListener.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.api.session.crypto
 
 /**
- * This listener notifies on new Megolm sessions being created
+ * This listener notifies on new Megolm sessions being created.
  */
 interface NewSessionListener {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/OutgoingKeyRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/OutgoingKeyRequest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..855f17a34fff1d165893a2e92db43555a1d2f52f
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/OutgoingKeyRequest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.api.session.crypto
+
+import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
+import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
+
+data class RequestReply(
+        val userId: String,
+        val fromDevice: String?,
+        val result: RequestResult
+)
+
+sealed class RequestResult {
+    data class  Success(val chainIndex: Int) : RequestResult()
+    data class Failure(val code: WithHeldCode) : RequestResult()
+}
+
+data class OutgoingKeyRequest(
+        var requestBody: RoomKeyRequestBody?,
+        // recipients for the request map of users to list of deviceId
+        val recipients: Map<String, List<String>>,
+        val fromIndex: Int,
+        // Unique id for this request. Used for both
+        // an id within the request for later pairing with a cancellation, and for
+        // the transaction id when sending the to_device messages to our local
+        val requestId: String, // current state of this request
+        val state: OutgoingRoomKeyRequestState,
+        val results: List<RequestReply>
+) {
+    /**
+     * Used only for log.
+     *
+     * @return the room id.
+     */
+    val roomId = requestBody?.roomId
+
+    /**
+     * Used only for log.
+     *
+     * @return the session id
+     */
+    val sessionId = requestBody?.sessionId
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OutgoingGossipingRequestState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/OutgoingRoomKeyRequestState.kt
similarity index 57%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OutgoingGossipingRequestState.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/OutgoingRoomKeyRequestState.kt
index 8c1bdf6768b5397f4457e113a09e91d20de5666f..6e80bdc1334c3df169e2594241d4c2fabcbd7f66 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OutgoingGossipingRequestState.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/OutgoingRoomKeyRequestState.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,14 +14,20 @@
  * limitations under the License.
  */
 
-package org.matrix.android.sdk.api.session.crypto.model
+package org.matrix.android.sdk.api.session.crypto
 
-enum class OutgoingGossipingRequestState {
+enum class OutgoingRoomKeyRequestState {
     UNSENT,
-    SENDING,
     SENT,
-    CANCELLING,
-    CANCELLED,
-    FAILED_TO_SEND,
-    FAILED_TO_CANCEL
+    SENT_THEN_CANCELED,
+    CANCELLATION_PENDING,
+    CANCELLATION_PENDING_AND_WILL_RESEND;
+
+    companion object {
+        fun pendingStates() = setOf(
+                UNSENT,
+                CANCELLATION_PENDING_AND_WILL_RESEND,
+                CANCELLATION_PENDING
+        )
+    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/attachments/ElementToDecrypt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/attachments/ElementToDecrypt.kt
index de168ac6e524b2501fc55bbdba6cfc50da073ccb..2591703e0c99f46211f0c01299cdc85c374e7c8c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/attachments/ElementToDecrypt.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/attachments/ElementToDecrypt.kt
@@ -35,7 +35,7 @@ fun EncryptedFileInfo.toElementToDecrypt(): ElementToDecrypt? {
 }
 
 /**
- * Represent data to decode an attachment
+ * Represent data to decode an attachment.
  */
 @Parcelize
 data class ElementToDecrypt(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt
index 46b131f613f009d19f8eb8ba370e9bd2cde103cc..5439389096bbd3cb6210f2c89d0509cd83562c05 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt
@@ -66,7 +66,7 @@ interface CrossSigningService {
     fun markMyMasterKeyAsTrusted()
 
     /**
-     * Sign one of your devices and upload the signature
+     * Sign one of your devices and upload the signature.
      */
     fun trustDevice(deviceId: String,
                     callback: MatrixCallback<Unit>)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CryptoCrossSigningKey.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CryptoCrossSigningKey.kt
index 11996e673e348b59e38b89eae91cd146447473e4..70ff76a4ef82a130dd58453181f5f74488fac4f9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CryptoCrossSigningKey.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CryptoCrossSigningKey.kt
@@ -93,7 +93,8 @@ data class CryptoCrossSigningKey(
                     userId = userId,
                     usages = listOf(usage.value),
                     keys = mapOf("ed25519:$b64key" to b64key),
-                    signatures = signMap)
+                    signatures = signMap
+            )
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt
index 9ff99f8dce144f8f5b83a8bb3327742e9ceba868..0d40490c3e6858a290d21c0937d828cb687ce1b1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt
@@ -23,7 +23,7 @@ import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
 
 interface KeysBackupService {
     /**
-     * Retrieve the current version of the backup from the homeserver
+     * Retrieve the current version of the backup from the homeserver.
      *
      * It can be different than keysBackupVersion.
      * @param callback Asynchronous callback
@@ -40,12 +40,12 @@ interface KeysBackupService {
                                 callback: MatrixCallback<KeysVersion>)
 
     /**
-     * Facility method to get the total number of locally stored keys
+     * Facility method to get the total number of locally stored keys.
      */
     fun getTotalNumbersOfKeys(): Int
 
     /**
-     * Facility method to get the number of backed up keys
+     * Facility method to get the number of backed up keys.
      */
     fun getTotalNumbersOfBackedUpKeys(): Int
 
@@ -68,7 +68,7 @@ interface KeysBackupService {
                            callback: MatrixCallback<KeysBackupVersionTrust>)
 
     /**
-     * Return the current progress of the backup
+     * Return the current progress of the backup.
      */
     fun getBackupProgress(progressListener: ProgressListener)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupStateListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupStateListener.kt
index a6f4bd0ec756619e0ec5dbb496c8568f8a4e9dc0..32216fe3f52baa6f515486881c78b0e1993d9e81 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupStateListener.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupStateListener.kt
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.session.crypto.keysbackup
 interface KeysBackupStateListener {
 
     /**
-     * The keys backup state has changed
+     * The keys backup state has changed.
      * @param newState the new state
      */
     fun onStateChange(newState: KeysBackupState)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupVersionTrustSignature.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupVersionTrustSignature.kt
index 219a328cfdd0411e406ab7685fdbab1ca7df7375..7127c8d3f45063112dbedd822a5e9809b81e45ac 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupVersionTrustSignature.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupVersionTrustSignature.kt
@@ -16,25 +16,35 @@
 
 package org.matrix.android.sdk.api.session.crypto.keysbackup
 
+import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
 import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
 
 /**
  * A signature in a `KeysBackupVersionTrust` object.
  */
-data class KeysBackupVersionTrustSignature(
-        /**
-         * The id of the device that signed the backup version.
-         */
-        val deviceId: String?,
-
-        /**
-         * The device that signed the backup version.
-         * Can be null if the device is not known.
-         */
-        val device: CryptoDeviceInfo?,
-
-        /**
-         * Flag to indicate the signature from this device is valid.
-         */
-        val valid: Boolean,
-)
+
+sealed class KeysBackupVersionTrustSignature {
+
+    data class DeviceSignature(
+            /**
+             * The id of the device that signed the backup version.
+             */
+            val deviceId: String?,
+
+            /**
+             * The device that signed the backup version.
+             * Can be null if the device is not known.
+             */
+            val device: CryptoDeviceInfo?,
+
+            /**
+             * Flag to indicate the signature from this device is valid.
+             */
+            val valid: Boolean) : KeysBackupVersionTrustSignature()
+
+    data class UserSignature(
+            val keyId: String?,
+            val cryptoCrossSigningKey: CryptoCrossSigningKey?,
+            val valid: Boolean
+    ) : KeysBackupVersionTrustSignature()
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysVersionResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysVersionResult.kt
index f283a34e98f665ded75c3cc32beb21c57a3d13a6..3d89bf9e2fec99e225acdc7e7093ae6ce9914b04 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysVersionResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysVersionResult.kt
@@ -30,8 +30,8 @@ data class KeysVersionResult(
         override val algorithm: String,
 
         /**
-         * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2"
-         * see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
+         * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2".
+         * @see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
          */
         @Json(name = "auth_data")
         override val authData: JsonDict,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/RecoveryKey.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/RecoveryKey.kt
index 85d6ef43653a8481134c19aa57bb87fc76c7d66c..9ad0bfc8b688585063dd10eedb9899bd17d9a43c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/RecoveryKey.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/RecoveryKey.kt
@@ -30,7 +30,7 @@ private const val CHAR_1 = 0x01.toByte()
 private const val RECOVERY_KEY_LENGTH = 2 + 32 + 1
 
 /**
- * Tell if the format of the recovery key is correct
+ * Tell if the format of the recovery key is correct.
  *
  * @param recoveryKey
  * @return true if the format of the recovery key is correct
@@ -40,7 +40,7 @@ fun isValidRecoveryKey(recoveryKey: String?): Boolean {
 }
 
 /**
- * Compute recovery key from curve25519 key
+ * Compute recovery key from curve25519 key.
  *
  * @param curve25519Key
  * @return the recovery key
@@ -69,7 +69,7 @@ fun computeRecoveryKey(curve25519Key: ByteArray): String {
 }
 
 /**
- * Please call [.isValidRecoveryKey] and ensure it returns true before calling this method
+ * Please call [.isValidRecoveryKey] and ensure it returns true before calling this method.
  *
  * @param recoveryKey the recovery key
  * @return curveKey, or null in case of error
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keyshare/GossipingRequestListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keyshare/GossipingRequestListener.kt
index 3cd36c2ce8cdd6a6bd9b18d70b6e9da1fe059171..cc160f8d859530950c3286829b7f9f9d5f98d782 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keyshare/GossipingRequestListener.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keyshare/GossipingRequestListener.kt
@@ -16,12 +16,11 @@
 
 package org.matrix.android.sdk.api.session.crypto.keyshare
 
-import org.matrix.android.sdk.api.session.crypto.model.IncomingRequestCancellation
 import org.matrix.android.sdk.api.session.crypto.model.IncomingRoomKeyRequest
-import org.matrix.android.sdk.api.session.crypto.model.IncomingSecretShareRequest
+import org.matrix.android.sdk.api.session.crypto.model.SecretShareRequest
 
 /**
- * Room keys events listener
+ * Room keys events listener.
  */
 interface GossipingRequestListener {
     /**
@@ -32,15 +31,15 @@ interface GossipingRequestListener {
     fun onRoomKeyRequest(request: IncomingRoomKeyRequest)
 
     /**
-     * Returns the secret value to be shared
+     * Returns the secret value to be shared.
      * @return true if is handled
      */
-    fun onSecretShareRequest(request: IncomingSecretShareRequest): Boolean
+    fun onSecretShareRequest(request: SecretShareRequest): Boolean
 
     /**
      * A room key request cancellation has been received.
      *
      * @param request the cancellation request
      */
-    fun onRoomKeyRequestCancellation(request: IncomingRequestCancellation)
+    fun onRequestCancelled(request: IncomingRoomKeyRequest)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/AuditTrail.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/AuditTrail.kt
new file mode 100644
index 0000000000000000000000000000000000000000..861f3bd30b0b6693fdb3b84c8f72a929ad3a756d
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/AuditTrail.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.api.session.crypto.model
+
+import com.squareup.moshi.JsonClass
+import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
+
+enum class TrailType {
+    OutgoingKeyForward,
+    IncomingKeyForward,
+    OutgoingKeyWithheld,
+    IncomingKeyRequest,
+    Unknown
+}
+
+interface AuditInfo {
+    val roomId: String
+    val sessionId: String
+    val senderKey: String
+    val alg: String
+    val userId: String
+    val deviceId: String
+}
+
+@JsonClass(generateAdapter = true)
+data class ForwardInfo(
+        override val roomId: String,
+        override val sessionId: String,
+        override val senderKey: String,
+        override val alg: String,
+        override val userId: String,
+        override val deviceId: String,
+        val chainIndex: Long?
+) : AuditInfo
+
+object UnknownInfo : AuditInfo {
+    override val roomId: String = ""
+    override val sessionId: String = ""
+    override val senderKey: String = ""
+    override val alg: String = ""
+    override val userId: String = ""
+    override val deviceId: String = ""
+}
+
+@JsonClass(generateAdapter = true)
+data class WithheldInfo(
+        override val roomId: String,
+        override val sessionId: String,
+        override val senderKey: String,
+        override val alg: String,
+        val code: WithHeldCode,
+        override val userId: String,
+        override val deviceId: String
+) : AuditInfo
+
+@JsonClass(generateAdapter = true)
+data class IncomingKeyRequestInfo(
+        override val roomId: String,
+        override val sessionId: String,
+        override val senderKey: String,
+        override val alg: String,
+        override val userId: String,
+        override val deviceId: String,
+        val requestId: String
+) : AuditInfo
+
+data class AuditTrail(
+        val ageLocalTs: Long,
+        val type: TrailType,
+        val info: AuditInfo
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/DeviceInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/DeviceInfo.kt
index 221d0793d94e88a92d82115a5a8772d61a91cb85..b144069b9947b49f5eeeb10959eab881c53f763d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/DeviceInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/DeviceInfo.kt
@@ -20,24 +20,24 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.api.interfaces.DatedObject
 
 /**
- * This class describes the device information
+ * This class describes the device information.
  */
 @JsonClass(generateAdapter = true)
 data class DeviceInfo(
         /**
-         * The owner user id (not documented and useless but the homeserver sent it. You should not need it)
+         * The owner user id (not documented and useless but the homeserver sent it. You should not need it).
          */
         @Json(name = "user_id")
         val userId: String? = null,
 
         /**
-         * The device id
+         * The device id.
          */
         @Json(name = "device_id")
         val deviceId: String? = null,
 
         /**
-         * The device display name
+         * The device display name.
          */
         @Json(name = "display_name")
         val displayName: String? = null,
@@ -49,7 +49,7 @@ data class DeviceInfo(
         val lastSeenTs: Long? = null,
 
         /**
-         * The last ip address
+         * The last ip address.
          */
         @Json(name = "last_seen_ip")
         val lastSeenIp: String? = null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/EncryptedFileInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/EncryptedFileInfo.kt
index 13ad1df47655389e5d2623508dc1b3bdce58054b..fb64c6f3384ccf679d5ee1cd0132b6caca5c4b28 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/EncryptedFileInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/EncryptedFileInfo.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * In Matrix specs: EncryptedFile
+ * In Matrix specs: EncryptedFile.
  */
 @JsonClass(generateAdapter = true)
 data class EncryptedFileInfo(
@@ -56,7 +56,7 @@ data class EncryptedFileInfo(
         val v: String? = null
 ) {
     /**
-     * Check what the spec tells us
+     * Check what the spec tells us.
      */
     fun isValid(): Boolean {
         if (url.isNullOrBlank()) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/EncryptedFileKey.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/EncryptedFileKey.kt
index 859c6ac43f0dc374a8c5fd6c32bc09abef705e0c..6308e3d615e6282340fcdc5cbfc5807e5df7da2a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/EncryptedFileKey.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/EncryptedFileKey.kt
@@ -52,7 +52,7 @@ data class EncryptedFileKey(
         val k: String? = null
 ) {
     /**
-     * Check what the spec tells us
+     * Check what the spec tells us.
      */
     fun isValid(): Boolean {
         if (alg != "A256CTR") {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/GossipingToDeviceObject.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/GossipingToDeviceObject.kt
index 1922b2bceef7eaec21ded77307eddcb423d2b764..ac575332da12ec254537939f63118b76d97328a7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/GossipingToDeviceObject.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/GossipingToDeviceObject.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.api.session.crypto.model
 
 /**
- * Interface representing an room key action request
+ * Interface representing an room key action request.
  * Note: this class cannot be abstract because of [org.matrix.androidsdk.core.JsonUtils.toRoomKeyShare]
  */
 interface GossipingToDeviceObject : SendToDeviceObject {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingRequestCancellation.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingRequestCancellation.kt
deleted file mode 100755
index ad11ef9a5e465b2cfc04a92af2ecd43511404dbf..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingRequestCancellation.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.api.session.crypto.model
-
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.events.model.toModel
-import org.matrix.android.sdk.internal.crypto.IncomingShareRequestCommon
-import org.matrix.android.sdk.internal.crypto.model.rest.ShareRequestCancellation
-
-/**
- * IncomingRequestCancellation describes the incoming room key cancellation.
- */
-data class IncomingRequestCancellation(
-        /**
-         * The user id
-         */
-        override val userId: String? = null,
-
-        /**
-         * The device id
-         */
-        override val deviceId: String? = null,
-
-        /**
-         * The request id
-         */
-        override val requestId: String? = null,
-        override val localCreationTimestamp: Long?
-) : IncomingShareRequestCommon {
-    companion object {
-        /**
-         * Factory
-         *
-         * @param event the event
-         * @param currentTimeMillis the current time in milliseconds
-         */
-        fun fromEvent(event: Event, currentTimeMillis: Long): IncomingRequestCancellation? {
-            return event.getClearContent()
-                    .toModel<ShareRequestCancellation>()
-                    ?.let {
-                        IncomingRequestCancellation(
-                                userId = event.senderId,
-                                deviceId = it.requestingDeviceId,
-                                requestId = it.requestId,
-                                localCreationTimestamp = event.ageLocalTs ?: currentTimeMillis
-                        )
-                    }
-        }
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingRoomKeyRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingRoomKeyRequest.kt
index 0b2c32284b05edd79316b5de883b5b5bb8e4d232..0c19d275cc375a4f47206fdaf0dc9966ce858d61 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingRoomKeyRequest.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingRoomKeyRequest.kt
@@ -16,68 +16,71 @@
 
 package org.matrix.android.sdk.api.session.crypto.model
 
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.events.model.toModel
-import org.matrix.android.sdk.internal.crypto.IncomingShareRequestCommon
+import org.matrix.android.sdk.internal.util.time.Clock
 
 /**
  * IncomingRoomKeyRequest class defines the incoming room keys request.
  */
 data class IncomingRoomKeyRequest(
         /**
-         * The user id
+         * The user id.
          */
-        override val userId: String? = null,
+        val userId: String? = null,
 
         /**
-         * The device id
+         * The device id.
          */
-        override val deviceId: String? = null,
+        val deviceId: String? = null,
 
         /**
-         * The request id
+         * The request id.
          */
-        override val requestId: String? = null,
+        val requestId: String? = null,
 
         /**
-         * The request body
+         * The request body.
          */
         val requestBody: RoomKeyRequestBody? = null,
 
-        val state: GossipingRequestState = GossipingRequestState.NONE,
-
-        /**
-         * The runnable to call to accept to share the keys
-         */
-        @Transient
-        var share: Runnable? = null,
-
-        /**
-         * The runnable to call to ignore the key share request.
-         */
-        @Transient
-        var ignore: Runnable? = null,
-        override val localCreationTimestamp: Long?
-) : IncomingShareRequestCommon {
+        val localCreationTimestamp: Long?
+) {
     companion object {
         /**
-         * Factory
+         * Factory.
          *
          * @param event the event
          * @param currentTimeMillis the current time in milliseconds
          */
-        fun fromEvent(event: Event, currentTimeMillis: Long): IncomingRoomKeyRequest? {
-            return event.getClearContent()
-                    .toModel<RoomKeyShareRequest>()
+        fun fromEvent(trail: AuditTrail): IncomingRoomKeyRequest? {
+            return trail
+                    .takeIf { it.type == TrailType.IncomingKeyRequest }
+                    ?.let {
+                        it.info as? IncomingKeyRequestInfo
+                    }
                     ?.let {
                         IncomingRoomKeyRequest(
-                                userId = event.senderId,
-                                deviceId = it.requestingDeviceId,
+                                userId = it.userId,
+                                deviceId = it.deviceId,
                                 requestId = it.requestId,
-                                requestBody = it.body ?: RoomKeyRequestBody(),
-                                localCreationTimestamp = event.ageLocalTs ?: currentTimeMillis
+                                requestBody = RoomKeyRequestBody(
+                                        algorithm = it.alg,
+                                        roomId = it.roomId,
+                                        senderKey = it.senderKey,
+                                        sessionId = it.sessionId
+                                ),
+                                localCreationTimestamp = trail.ageLocalTs
                         )
                     }
         }
+
+        internal fun fromRestRequest(senderId: String, request: RoomKeyShareRequest, clock: Clock): IncomingRoomKeyRequest? {
+            return IncomingRoomKeyRequest(
+                    userId = senderId,
+                    deviceId = request.requestingDeviceId,
+                    requestId = request.requestId,
+                    requestBody = request.body,
+                    localCreationTimestamp = clock.epochMillis()
+            )
+        }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingSecretShareRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingSecretShareRequest.kt
deleted file mode 100755
index 80f70c83f3a6e7671bc53cc463b95b448ebe7d4e..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingSecretShareRequest.kt
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.api.session.crypto.model
-
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.events.model.toModel
-import org.matrix.android.sdk.internal.crypto.IncomingShareRequestCommon
-
-/**
- * IncomingSecretShareRequest class defines the incoming secret keys request.
- */
-data class IncomingSecretShareRequest(
-        /**
-         * The user id
-         */
-        override val userId: String? = null,
-
-        /**
-         * The device id
-         */
-        override val deviceId: String? = null,
-
-        /**
-         * The request id
-         */
-        override val requestId: String? = null,
-
-        /**
-         * The request body
-         */
-        val secretName: String? = null,
-
-        /**
-         * The runnable to call to accept to share the keys
-         */
-        @Transient
-        var share: ((String) -> Unit)? = null,
-
-        /**
-         * The runnable to call to ignore the key share request.
-         */
-        @Transient
-        var ignore: Runnable? = null,
-
-        override val localCreationTimestamp: Long?
-
-) : IncomingShareRequestCommon {
-    companion object {
-        /**
-         * Factory
-         *
-         * @param event the event
-         * @param currentTimeMillis the current time in milliseconds
-         */
-        fun fromEvent(event: Event, currentTimeMillis: Long): IncomingSecretShareRequest? {
-            return event.getClearContent()
-                    .toModel<SecretShareRequest>()
-                    ?.let {
-                        IncomingSecretShareRequest(
-                                userId = event.senderId,
-                                deviceId = it.requestingDeviceId,
-                                requestId = it.requestId,
-                                secretName = it.secretName,
-                                localCreationTimestamp = event.ageLocalTs ?: currentTimeMillis
-                        )
-                    }
-        }
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXDeviceInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXDeviceInfo.kt
index 286ab2b7d518ef0f55dd33b5bc569dbcc1ea5241..a5a581d240279ed6e1137d0d19af94b4a42261c6 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXDeviceInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXDeviceInfo.kt
@@ -30,7 +30,7 @@ data class MXDeviceInfo(
         val deviceId: String,
 
         /**
-         * the user id
+         * the user id.
          */
         @Json(name = "user_id")
         val userId: String,
@@ -66,7 +66,7 @@ data class MXDeviceInfo(
         val verified: Int = DEVICE_VERIFICATION_UNKNOWN
 ) : Serializable {
     /**
-     * Tells if the device is unknown
+     * Tells if the device is unknown.
      *
      * @return true if the device is unknown
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXEncryptEventContentResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXEncryptEventContentResult.kt
index 706e40a769e485b298edb2911ac828b30e9bab0b..4cfcc01a26f1e2b87f0fbe379453942464fa557f 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXEncryptEventContentResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXEncryptEventContentResult.kt
@@ -20,11 +20,11 @@ import org.matrix.android.sdk.api.session.events.model.Content
 
 data class MXEncryptEventContentResult(
         /**
-         * The encrypted event content
+         * The encrypted event content.
          */
         val eventContent: Content,
         /**
-         * the event type
+         * The event type.
          */
         val eventType: String
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXUsersDevicesMap.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXUsersDevicesMap.kt
index dc5567e908d760354ff95efd1dc35b137e41de8b..744fe74d0da947bf5b0b2d141cf340f4a8b6e6e9 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXUsersDevicesMap.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXUsersDevicesMap.kt
@@ -31,7 +31,7 @@ class MXUsersDevicesMap<E> {
         get() = map.isEmpty()
 
     /**
-     * Provides the device ids list for a user id
+     * Provides the device ids list for a user id.
      * FIXME Should maybe return emptyList and not null, to avoid many !! in the code
      *
      * @param userId the user id
@@ -44,7 +44,7 @@ class MXUsersDevicesMap<E> {
     }
 
     /**
-     * Provides the object for a device id and a user Id
+     * Provides the object for a device id and a user Id.
      *
      * @param deviceId the device id
      * @param userId   the object id
@@ -57,7 +57,7 @@ class MXUsersDevicesMap<E> {
     }
 
     /**
-     * Set an object for a dedicated user Id and device Id
+     * Set an object for a dedicated user Id and device Id.
      *
      * @param userId   the user Id
      * @param deviceId the device id
@@ -71,7 +71,7 @@ class MXUsersDevicesMap<E> {
     }
 
     /**
-     * Defines the objects map for a user Id
+     * Defines the objects map for a user Id.
      *
      * @param objectsPerDevices the objects maps
      * @param userId            the user id
@@ -87,7 +87,7 @@ class MXUsersDevicesMap<E> {
     }
 
     /**
-     * Removes objects for a dedicated user
+     * Removes objects for a dedicated user.
      *
      * @param userId the user id.
      */
@@ -98,14 +98,14 @@ class MXUsersDevicesMap<E> {
     }
 
     /**
-     * Clear the internal dictionary
+     * Clear the internal dictionary.
      */
     fun removeAllObjects() {
         map.clear()
     }
 
     /**
-     * Add entries from another MXUsersDevicesMap
+     * Add entries from another MXUsersDevicesMap.
      *
      * @param other the other one
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OlmDecryptionResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OlmDecryptionResult.kt
index 9cf2bf75fbd27206d91b683ebd0e46b75edd14b9..a26f6606edd1a8f7fea8108520ad9a277619b516 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OlmDecryptionResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OlmDecryptionResult.kt
@@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.util.JsonDict
 @JsonClass(generateAdapter = true)
 data class OlmDecryptionResult(
         /**
-         * The decrypted payload (with properties 'type', 'content')
+         * The decrypted payload (with properties 'type', 'content').
          */
         @Json(name = "payload") val payload: JsonDict? = null,
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OutgoingRoomKeyRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OutgoingRoomKeyRequest.kt
deleted file mode 100755
index 5f35cc908f9bd63d736cdc16082848972d18069d..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OutgoingRoomKeyRequest.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.api.session.crypto.model
-
-import com.squareup.moshi.JsonClass
-import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequest
-
-/**
- * Represents an outgoing room key request
- */
-@JsonClass(generateAdapter = true)
-data class OutgoingRoomKeyRequest(
-        // RequestBody
-        val requestBody: RoomKeyRequestBody?,
-        // list of recipients for the request
-        override val recipients: Map<String, List<String>>,
-        // Unique id for this request. Used for both
-        // an id within the request for later pairing with a cancellation, and for
-        // the transaction id when sending the to_device messages to our local
-        override val requestId: String, // current state of this request
-        override val state: OutgoingGossipingRequestState
-        // transaction id for the cancellation, if any
-        // override var cancellationTxnId: String? = null
-) : OutgoingGossipingRequest {
-
-    /**
-     * Used only for log.
-     *
-     * @return the room id.
-     */
-    val roomId: String?
-        get() = requestBody?.roomId
-
-    /**
-     * Used only for log.
-     *
-     * @return the session id
-     */
-    val sessionId: String?
-        get() = requestBody?.sessionId
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomKeyRequestBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomKeyRequestBody.kt
index 15163248dc94365e5faf0569dafacbe3ac7d551e..8352949263d3379de0bc4a5228f2fff34fcd11f0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomKeyRequestBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomKeyRequestBody.kt
@@ -21,7 +21,7 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.internal.di.MoshiProvider
 
 /**
- * Class representing an room key request body content
+ * Class representing an room key request body content.
  */
 @JsonClass(generateAdapter = true)
 data class RoomKeyRequestBody(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomKeyShareRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomKeyShareRequest.kt
index b6bb4c55af9f1f5acf217265968b92d429555d93..adbe831a07ffbbdf3be42e69049e934d7cd428f1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomKeyShareRequest.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomKeyShareRequest.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing a room key request content
+ * Class representing a room key request content.
  */
 @JsonClass(generateAdapter = true)
 data class RoomKeyShareRequest(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/SecretShareRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/SecretShareRequest.kt
index 6009077806146c541581a6a99618de17dd5e3d20..263a7b16e4d2b22fca448d548f6fd4e43ef8d410 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/SecretShareRequest.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/SecretShareRequest.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing a room key request content
+ * Class representing a room key request content.
  */
 @JsonClass(generateAdapter = true)
 data class SecretShareRequest(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/PendingVerificationRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/PendingVerificationRequest.kt
index be450b9d03c2a9e43050353841bdc3697d4fd002..7db450e8613b250686a21497dd77e90f1ca684d8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/PendingVerificationRequest.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/PendingVerificationRequest.kt
@@ -22,7 +22,7 @@ import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_SAS
 import java.util.UUID
 
 /**
- * Stores current pending verification requests
+ * Stores current pending verification requests.
  */
 data class PendingVerificationRequest(
         val ageLocalTs: Long,
@@ -45,7 +45,7 @@ data class PendingVerificationRequest(
     val isFinished: Boolean = isSuccessful || cancelConclusion != null
 
     /**
-     * SAS is supported if I support it and the other party support it
+     * SAS is supported if I support it and the other party support it.
      */
     fun isSasSupported(): Boolean {
         return requestInfo?.methods?.contains(VERIFICATION_METHOD_SAS).orFalse() &&
@@ -53,7 +53,7 @@ data class PendingVerificationRequest(
     }
 
     /**
-     * Other can show QR code if I can scan QR code and other can show QR code
+     * Other can show QR code if I can scan QR code and other can show QR code.
      */
     fun otherCanShowQrCode(): Boolean {
         return if (isIncoming) {
@@ -66,7 +66,7 @@ data class PendingVerificationRequest(
     }
 
     /**
-     * Other can scan QR code if I can show QR code and other can scan QR code
+     * Other can scan QR code if I can show QR code and other can scan QR code.
      */
     fun otherCanScanQrCode(): Boolean {
         return if (isIncoming) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/QrCodeVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/QrCodeVerificationTransaction.kt
index 37855099be34d516bc61dea321c0c9528ce12e26..06bac4109b4783e777f70a289401de893cae8d04 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/QrCodeVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/QrCodeVerificationTransaction.kt
@@ -19,22 +19,22 @@ package org.matrix.android.sdk.api.session.crypto.verification
 interface QrCodeVerificationTransaction : VerificationTransaction {
 
     /**
-     * To use to display a qr code, for the other user to scan it
+     * To use to display a qr code, for the other user to scan it.
      */
     val qrCodeText: String?
 
     /**
-     * Call when you have scan the other user QR code
+     * Call when you have scan the other user QR code.
      */
     fun userHasScannedOtherQrCode(otherQrCodeText: String)
 
     /**
-     * Call when you confirm that other user has scanned your QR code
+     * Call when you confirm that other user has scanned your QR code.
      */
     fun otherUserScannedMyQrCode()
 
     /**
-     * Call when you do not confirm that other user has scanned your QR code
+     * Call when you do not confirm that other user has scanned your QR code.
      */
     fun otherUserDidNotScannedMyQrCode()
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/SasVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/SasVerificationTransaction.kt
index da546be68f39a984119811175a896e02adcf5cca..095b4208f8654e458d0aa1b4332594f100bd8e17 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/SasVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/SasVerificationTransaction.kt
@@ -28,7 +28,7 @@ interface SasVerificationTransaction : VerificationTransaction {
 
     /**
      * To be called by the client when the user has verified that
-     * both short codes do match
+     * both short codes do match.
      */
     fun userHasVerifiedShortCode()
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationMethod.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationMethod.kt
index 4efec93a34cf3b995167eaa3e2fe316480430e4e..f2de2c4b47ed2fedd920021d9dcd21e5d9a6a9ee 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationMethod.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationMethod.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.api.session.crypto.verification
 
 /**
- * Verification methods
+ * Verification methods.
  */
 enum class VerificationMethod {
     // Use it when your application supports the SAS verification method
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt
index ec67e4b31d143adfdc048d6eea232d8be0376546..321ec7309403b5a961b96a7f26ae85e214b32fb2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt
@@ -34,7 +34,7 @@ interface VerificationService {
     fun removeListener(listener: Listener)
 
     /**
-     * Mark this device as verified manually
+     * Mark this device as verified manually.
      */
     fun markedLocallyAsManuallyVerified(userId: String, deviceID: String)
 
@@ -52,7 +52,7 @@ interface VerificationService {
                              transactionId: String?): String?
 
     /**
-     * Request key verification with another user via room events (instead of the to-device API)
+     * Request key verification with another user via room events (instead of the to-device API).
      */
     fun requestKeyVerificationInDMs(methods: List<VerificationMethod>,
                                     otherUserId: String,
@@ -81,7 +81,7 @@ interface VerificationService {
                                   otherDeviceId: String): String
 
     /**
-     * Returns false if the request is unknown
+     * Returns false if the request is unknown.
      */
     fun readyPendingVerificationInDMs(methods: List<VerificationMethod>,
                                       otherUserId: String,
@@ -89,7 +89,7 @@ interface VerificationService {
                                       transactionId: String): Boolean
 
     /**
-     * Returns false if the request is unknown
+     * Returns false if the request is unknown.
      */
     fun readyPendingVerification(methods: List<VerificationMethod>,
                                  otherUserId: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTransaction.kt
index 4d35bc44ace9e74092e61b52283bfa0b18b655d2..b68a82c604013a5a82d6398567c7a0a19d8af513 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTransaction.kt
@@ -28,7 +28,7 @@ interface VerificationTransaction {
     val isIncoming: Boolean
 
     /**
-     * User wants to cancel the transaction
+     * User wants to cancel the transaction.
      */
     fun cancel()
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt
index 1ce51a2bded08c7c43c1e83ccd690bc8da7a6779..16bdbd3432bd5bfb1d67a999af754803ff361c0a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt
@@ -62,7 +62,7 @@ inline fun <reified T> Content?.toModel(catchError: Boolean = true): T? {
 }
 
 /**
- * This methods is a facility method to map a model to a json Content
+ * This methods is a facility method to map a model to a json Content.
  */
 @Suppress("UNCHECKED_CAST")
 inline fun <reified T> T.toContent(): Content {
@@ -123,7 +123,7 @@ data class Event(
     var ageLocalTs: Long? = null
 
     /**
-     * Copy all fields, including transient fields
+     * Copy all fields, including transient fields.
      */
     fun copyAll(): Event {
         return copy().also {
@@ -227,14 +227,14 @@ data class Event(
     }
 
     /**
-     * Determines whether or not current event has mentioned the user
+     * Determines whether or not current event has mentioned the user.
      */
     fun isUserMentioned(userId: String): Boolean {
         return getDecryptedValue("formatted_body")?.contains(userId) ?: false
     }
 
     /**
-     * Decrypt the message, or return the pure payload value if there is no encryption
+     * Decrypt the message, or return the pure payload value if there is no encryption.
      */
     private fun getDecryptedValue(key: String = "body"): String? {
         return if (isEncrypted()) {
@@ -247,7 +247,7 @@ data class Event(
     }
 
     /**
-     * Tells if the event is redacted
+     * Tells if the event is redacted.
      */
     fun isRedacted() = unsignedData?.redactedEvent != null
 
@@ -305,7 +305,7 @@ data class Event(
 
 /**
  * Return the value of "content.msgtype", if the Event type is "m.room.message"
- * and if the content has it, and if it is a String
+ * and if the content has it, and if it is a String.
  */
 fun Event.getMsgType(): String? {
     if (getClearType() != EventType.MESSAGE) return null
@@ -386,13 +386,13 @@ fun Event.getRelationContent(): RelationDefaultContent? {
 }
 
 /**
- * Returns the poll question or null otherwise
+ * Returns the poll question or null otherwise.
  */
 fun Event.getPollQuestion(): String? =
         getPollContent()?.getBestPollCreationInfo()?.question?.getBestQuestion()
 
 /**
- * Returns the relation content for a specific type or null otherwise
+ * Returns the relation content for a specific type or null otherwise.
  */
 fun Event.getRelationContentForType(type: String): RelationDefaultContent? =
         getRelationContent()?.takeIf { it.type == type }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/RelationType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/RelationType.kt
index 74dc74b294964e2669c558405f2bec33c59eb386..3db9262c5b102fc2da4399f65d4398a4c0106c17 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/RelationType.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/RelationType.kt
@@ -16,7 +16,7 @@
 package org.matrix.android.sdk.api.session.events.model
 
 /**
- * Constants defining known event relation types from Matrix specifications
+ * Constants defining known event relation types from Matrix specifications.
  */
 object RelationType {
     /** Lets you define an event which annotates an existing event.*/
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/EncryptedEventContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/EncryptedEventContent.kt
index 4f39bb61e14871cc5d79b44e94fa57b994fc6026..b8388ea00246b57e0c41c26725ec5879d8f8eb49 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/EncryptedEventContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/EncryptedEventContent.kt
@@ -20,37 +20,37 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
 
 /**
- * Class representing an encrypted event content
+ * Class representing an encrypted event content.
  */
 @JsonClass(generateAdapter = true)
 data class EncryptedEventContent(
 
         /**
-         * the used algorithm
+         * The used algorithm.
          */
         @Json(name = "algorithm")
         val algorithm: String? = null,
 
         /**
-         * The encrypted event
+         * The encrypted event.
          */
         @Json(name = "ciphertext")
         val ciphertext: String? = null,
 
         /**
-         * The device id
+         * The device id.
          */
         @Json(name = "device_id")
         val deviceId: String? = null,
 
         /**
-         * the sender key
+         * The sender key.
          */
         @Json(name = "sender_key")
         val senderKey: String? = null,
 
         /**
-         * The session id
+         * The session id.
          */
         @Json(name = "session_id")
         val sessionId: String? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/EncryptionEventContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/EncryptionEventContent.kt
index 103293ba8316fc88949389b51fcb9f92a1996f92..321afd186d381ebdca70472470d00fac066a06a3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/EncryptionEventContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/EncryptionEventContent.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing an encrypted event content
+ * Class representing an encrypted event content.
  */
 @JsonClass(generateAdapter = true)
 data class EncryptionEventContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/OlmEventContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/OlmEventContent.kt
index b972dd20bbf622a32b86e3b2ae2559dd52452d9a..65e81281821165786de143cfea58b6290f2ed602 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/OlmEventContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/OlmEventContent.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing an encrypted event content
+ * Class representing an encrypted event content.
  */
 @JsonClass(generateAdapter = true)
 data class OlmEventContent(
@@ -30,7 +30,7 @@ data class OlmEventContent(
         val ciphertext: Map<String, Any>? = null,
 
         /**
-         * the sender key
+         * the sender key.
          */
         @Json(name = "sender_key")
         val senderKey: String? = null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/OlmPayloadContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/OlmPayloadContent.kt
index 6060ab5c4b258f6a023818e04014114db47ebec2..c3d8a5a800cec01a9aa17a07ba9c756de8ef120e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/OlmPayloadContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/OlmPayloadContent.kt
@@ -20,36 +20,36 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.internal.di.MoshiProvider
 
 /**
- * Class representing the OLM payload content
+ * Class representing the OLM payload content.
  */
 @JsonClass(generateAdapter = true)
 data class OlmPayloadContent(
         /**
-         * The room id
+         * The room id.
          */
         @Json(name = "room_id")
         val roomId: String? = null,
 
         /**
-         * The sender
+         * The sender.
          */
         @Json(name = "sender")
         val sender: String? = null,
 
         /**
-         * The recipient
+         * The recipient.
          */
         @Json(name = "recipient")
         val recipient: String? = null,
 
         /**
-         * the recipient keys
+         * The recipient keys.
          */
         @Json(name = "recipient_keys")
         val recipientKeys: Map<String, String>? = null,
 
         /**
-         * The keys
+         * The keys.
          */
         @Json(name = "keys")
         val keys: Map<String, String>? = null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyContent.kt
index 43a47b818f6bf856adf286a7a366ff72e2990456..0830a566ab86d6bc301a5f94004f93b3bf369819 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyContent.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing an sharekey content
+ * Class representing an sharekey content.
  */
 @JsonClass(generateAdapter = true)
 data class RoomKeyContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyWithHeldContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyWithHeldContent.kt
index a577daf9e42cf0cb2729b384eed455feea447da9..d58c3614a70af1f0ef522243c0595dcacc1b79d6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyWithHeldContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyWithHeldContent.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing an sharekey content
+ * Class representing an sharekey content.
  */
 @JsonClass(generateAdapter = true)
 data class RoomKeyWithHeldContent(
@@ -52,7 +52,13 @@ data class RoomKeyWithHeldContent(
         /**
          *  A human-readable reason for why the key was not sent. The receiving client should only use this string if it does not understand the code.
          */
-        @Json(name = "reason") val reason: String? = null
+        @Json(name = "reason") val reason: String? = null,
+
+        /**
+         * the device ID of the device sending the m.room_key.withheld message
+         * MSC3735.
+         */
+        @Json(name = "from_device") val fromDevice: String? = null
 
 ) {
     val code: WithHeldCode?
@@ -63,23 +69,23 @@ data class RoomKeyWithHeldContent(
 
 enum class WithHeldCode(val value: String) {
     /**
-     * the user/device was blacklisted
+     * the user/device was blacklisted.
      */
     BLACKLISTED("m.blacklisted"),
 
     /**
-     * the user/devices is unverified
+     * the user/devices is unverified.
      */
     UNVERIFIED("m.unverified"),
 
     /**
      * the user/device is not allowed have the key. For example, this would usually be sent in response
-     * to a key request if the user was not in the room when the message was sent
+     * to a key request if the user was not in the room when the message was sent.
      */
     UNAUTHORISED("m.unauthorised"),
 
     /**
-     * Sent in reply to a key request if the device that the key is requested from does not have the requested key
+     * Sent in reply to a key request if the device that the key is requested from does not have the requested key.
      */
     UNAVAILABLE("m.unavailable"),
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/SecretSendEventContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/SecretSendEventContent.kt
index 5099aba403066b7747271e23451b61a63f17c1c7..be9d9d638c9e1858c319d39303cbe9a333ecf344 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/SecretSendEventContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/SecretSendEventContent.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing an encrypted event content
+ * Class representing an encrypted event content.
  */
 @JsonClass(generateAdapter = true)
 data class SecretSendEventContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/FileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/FileService.kt
index e3ccbad2490b712587f7e15779c3524ad8ea30f3..84a99908268ecccf607f51473b7e9cb90ddea35b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/FileService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/FileService.kt
@@ -68,11 +68,12 @@ interface FileService {
                     mxcUrl = messageContent.getFileUrl(),
                     fileName = messageContent.getFileName(),
                     mimeType = messageContent.mimeType,
-                    elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt())
+                    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)
+     * (if not other app won't be able to access it).
      */
     fun getTemporarySharableURI(mxcUrl: String?,
                                 fileName: String,
@@ -105,17 +106,17 @@ interface FileService {
             )
 
     /**
-     * Clears all the files downloaded by the service, including decrypted files
+     * Clears all the files downloaded by the service, including decrypted files.
      */
     fun clearCache()
 
     /**
-     * Clears all the decrypted files by the service
+     * Clears all the decrypted files by the service.
      */
     fun clearDecryptedCache()
 
     /**
-     * Get size of cached files
+     * Get size of cached files.
      */
     fun getCacheSize(): Long
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/MatrixSDKFileProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/MatrixSDKFileProvider.kt
index ee1550d1db905029eb9a82767f2033af92a916e2..113bf9333f5a58fd4bd302024f87198ec51ad1b3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/MatrixSDKFileProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/MatrixSDKFileProvider.kt
@@ -21,7 +21,7 @@ import androidx.core.content.FileProvider
 
 /**
  * We have to declare our own file provider to avoid collision with apps using the sdk
- * and having their own
+ * and having their own.
  */
 class MatrixSDKFileProvider : FileProvider() {
     override fun getType(uri: Uri): String? {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupService.kt
index a96466603c5eadbe248f25f871e00835685a513b..1968af222aa1c6c44912302ad0561f8f3433b94a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupService.kt
@@ -23,16 +23,15 @@ import org.matrix.android.sdk.api.session.group.model.GroupSummary
  * This interface defines methods to get groups. It's implemented at the session level.
  */
 interface GroupService {
-
     /**
-     * Get a group from a groupId
+     * Get a group from a groupId.
      * @param groupId the groupId to look for.
      * @return the group with groupId or null
      */
     fun getGroup(groupId: String): Group?
 
     /**
-     * Get a groupSummary from a groupId
+     * Get a groupSummary from a groupId.
      * @param groupId the groupId to look for.
      * @return the groupSummary with groupId or null
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupSummaryQueryParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupSummaryQueryParams.kt
index 0761a22c777ba153396c9e52c18466bd7cbe11d9..5104b3ee5371a5b0e53c2a892f82e408e27dcaed 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupSummaryQueryParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/GroupSummaryQueryParams.kt
@@ -24,7 +24,7 @@ fun groupSummaryQueryParams(init: (GroupSummaryQueryParams.Builder.() -> Unit) =
 }
 
 /**
- * This class can be used to filter group summaries
+ * This class can be used to filter group summaries.
  */
 data class GroupSummaryQueryParams(
         val displayName: QueryStringValue,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt
index 597c1a0ca8df0087f0b6d44a0f5eceefadb4eec6..5b06fdacae2c938fa9126c3a398ac94d488d309e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt
@@ -34,25 +34,25 @@ data class HomeServerCapabilities(
          */
         val canChange3pid: Boolean = true,
         /**
-         * Max size of file which can be uploaded to the homeserver in bytes. [MAX_UPLOAD_FILE_SIZE_UNKNOWN] if unknown or not retrieved yet
+         * Max size of file which can be uploaded to the homeserver in bytes. [MAX_UPLOAD_FILE_SIZE_UNKNOWN] if unknown or not retrieved yet.
          */
         val maxUploadFileSize: Long = MAX_UPLOAD_FILE_SIZE_UNKNOWN,
         /**
-         * Last version identity server and binding supported
+         * Last version identity server and binding supported.
          */
         val lastVersionIdentityServerSupported: Boolean = false,
         /**
-         * Default identity server url, provided in Wellknown
+         * Default identity server url, provided in Wellknown.
          */
         val defaultIdentityServerUrl: String? = null,
         /**
-         * Room versions supported by the server
+         * Room versions supported by the server.
          * This capability describes the default and available room versions a server supports, and at what level of stability.
          * Clients should make use of this capability to determine if users need to be encouraged to upgrade their rooms.
          */
         val roomVersions: RoomVersionCapabilities? = null,
         /**
-         * True if the home server support threading
+         * True if the home server support threading.
          */
         val canUseThreading: Boolean = false
 ) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesService.kt
index f12cbcd6db12b79a7a8dabf6436447bc5317869e..9d2c48e194f930a7f47e0f5642a7f602b9e59f76 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesService.kt
@@ -22,12 +22,12 @@ package org.matrix.android.sdk.api.session.homeserver
 interface HomeServerCapabilitiesService {
 
     /**
-     * Force a refresh of the stored data
+     * Force a refresh of the stored data.
      */
     suspend fun refreshHomeServerCapabilities()
 
     /**
-     * Get the HomeServer capabilities
+     * Get the HomeServer capabilities.
      */
     fun getHomeServerCapabilities(): HomeServerCapabilities
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt
index fdcb30a5c826390f8a0e1b68053d6586992f1e44..c03b42e6c894037487126dc7e7b133be156ace9b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt
@@ -19,13 +19,13 @@ package org.matrix.android.sdk.api.session.identity
 import org.matrix.android.sdk.api.session.identity.model.SignInvitationResult
 
 /**
- * Provides access to the identity server configuration and services identity server can provide
+ * Provides access to the identity server configuration and services identity server can provide.
  */
 interface IdentityService {
     /**
      * Return the default identity server of the user, which may have been provided at login time by the homeserver,
-     * or by the Well-known setup of the homeserver
-     * It may be different from the current configured identity server
+     * or by the Well-known setup of the homeserver.
+     * It may be different from the current configured identity server.
      */
     fun getDefaultIdentityServer(): String?
 
@@ -35,9 +35,9 @@ interface IdentityService {
     fun getCurrentIdentityServerUrl(): String?
 
     /**
-     * Check if the identity server is valid
-     * See https://matrix.org/docs/spec/identity_service/latest#status-check
-     * Matrix Android SDK2 only supports identity server API v2
+     * Check if the identity server is valid.
+     * See https://matrix.org/docs/spec/identity_service/latest#status-check.
+     * Matrix Android SDK2 only supports identity server API v2.
      */
     suspend fun isValidIdentityServer(url: String)
 
@@ -52,12 +52,12 @@ interface IdentityService {
     suspend fun setNewIdentityServer(url: String): String
 
     /**
-     * Disconnect (logout) from the current identity server
+     * Disconnect (logout) from the current identity server.
      */
     suspend fun disconnect()
 
     /**
-     * This will ask the identity server to send an email or an SMS to let the user confirm he owns the ThreePid
+     * This will ask the identity server to send an email or an SMS to let the user confirm he owns the ThreePid.
      */
     suspend fun startBindThreePid(threePid: ThreePid)
 
@@ -67,32 +67,32 @@ interface IdentityService {
     suspend fun cancelBindThreePid(threePid: ThreePid)
 
     /**
-     * This will ask the identity server to send an new email or a new SMS to let the user confirm he owns the ThreePid
+     * This will ask the identity server to send an new email or a new SMS to let the user confirm he owns the ThreePid.
      */
     suspend fun sendAgainValidationCode(threePid: ThreePid)
 
     /**
-     * Submit the code that the identity server has sent to the user (in email or SMS)
+     * Submit the code that the identity server has sent to the user (in email or SMS).
      * Once successful, you will have to call [finalizeBindThreePid]
      * @param code the code sent to the user
      */
     suspend fun submitValidationToken(threePid: ThreePid, code: String)
 
     /**
-     * This will perform the actual association of ThreePid and Matrix account
+     * This will perform the actual association of ThreePid and Matrix account.
      */
     suspend fun finalizeBindThreePid(threePid: ThreePid)
 
     /**
-     * Unbind a threePid
-     * The request will actually be done on the homeserver
+     * Unbind a threePid.
+     * The request will actually be done on the homeserver.
      */
     suspend fun unbindThreePid(threePid: ThreePid)
 
     /**
-     * Search MatrixId of users providing email and phone numbers
-     * Note the the user consent has to be set to true, or it will throw a UserConsentNotProvided failure
-     * Application has to explicitly ask for the user consent, and the answer can be stored using [setUserConsent]
+     * Search MatrixId of users providing email and phone numbers.
+     * Note the the user consent has to be set to true, or it will throw a UserConsentNotProvided failure.
+     * Application has to explicitly ask for the user consent, and the answer can be stored using [setUserConsent].
      * Please see https://support.google.com/googleplay/android-developer/answer/9888076?hl=en for more details.
      */
     suspend fun lookUp(threePids: List<ThreePid>): List<FoundThreePid>
@@ -115,8 +115,8 @@ interface IdentityService {
     fun setUserConsent(newValue: Boolean)
 
     /**
-     * Get the status of the current user's threePid
-     * A lookup will be performed, but also pending binding state will be restored
+     * Get the status of the current user's threePid.
+     * A lookup will be performed, but also pending binding state will be restored.
      *
      * @param threePids the list of threePid the user owns (retrieved form the homeserver)
      * @return a map of ThreePid -> SharedState
@@ -126,7 +126,7 @@ interface IdentityService {
     /**
      * When one performs a 3pid invite and the third party identifier is unknown, the home server
      * will store the invitation in the Identity server and store some information in the room state membership event.
-     * The email invite will contains the token and secret that can be used to claim the stored invitation
+     * The email invite will contains the token and secret that can be used to claim the stored invitation.
      *
      * To aid clients who may not be able to perform crypto themselves,
      * the identity server offers some crypto functionality to help in accepting invitations.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/model/SignInvitationResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/model/SignInvitationResult.kt
index b1662b9cf821349678afb5b0214fa9f8336773d6..28d9d154f3a4c74e446c29294b6fcf622aade855 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/model/SignInvitationResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/model/SignInvitationResult.kt
@@ -33,7 +33,7 @@ data class SignInvitationResult(
          */
         val signatures: Map<String, *>,
         /**
-         * The token for the invitation
+         * The token for the invitation.
          */
         val token: String
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/SyncStatusService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/SyncStatusService.kt
index 759813939f432691cc4e9e389d362bf831759704..7006e117512bf4405c7f17e52f2334f2c52f57a3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/SyncStatusService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/SyncStatusService.kt
@@ -23,7 +23,7 @@ interface SyncStatusService {
 
     sealed class Status {
         /**
-         * For initial sync
+         * For initial sync.
          */
         abstract class InitialSyncStatus : Status()
 
@@ -34,7 +34,7 @@ interface SyncStatusService {
         ) : InitialSyncStatus()
 
         /**
-         * For incremental sync
+         * For incremental sync.
          */
         abstract class IncrementalSyncStatus : Status()
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/integrationmanager/IntegrationManagerConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/integrationmanager/IntegrationManagerConfig.kt
index 069ed7427c534dffef46d226d31fb960772f852e..b04b31af3b23c795d5120a9fd5a7da54073722ee 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/integrationmanager/IntegrationManagerConfig.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/integrationmanager/IntegrationManagerConfig.kt
@@ -30,17 +30,17 @@ data class IntegrationManagerConfig(
      */
     enum class Kind {
         /**
-         * Defined in UserAccountData
+         * Defined in UserAccountData.
          */
         ACCOUNT,
 
         /**
-         * Defined in Wellknown
+         * Defined in Wellknown.
          */
         HOMESERVER,
 
         /**
-         * Fallback value, hardcoded by the SDK
+         * Fallback value, hardcoded by the SDK.
          */
         DEFAULT
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/MediaService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/MediaService.kt
index 3b3ef57d738da17fe793709884f74e825181886a..2e53e67b0c2cec9a7cbb3cdd34c369472f7ce009 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/MediaService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/MediaService.kt
@@ -36,7 +36,7 @@ interface MediaService {
     suspend fun getRawPreviewUrl(url: String, timestamp: Long?): JsonDict
 
     /**
-     * Get Url Preview data from the homeserver, or from cache, depending on the cache strategy
+     * Get Url Preview data from the homeserver, or from cache, depending on the cache strategy.
      * @param url The url to get the preview data from
      * @param timestamp The optional timestamp. Note that this parameter is not taken into account
      * if the data is already in cache and the cache strategy allow to use it
@@ -45,7 +45,7 @@ interface MediaService {
     suspend fun getPreviewUrl(url: String, timestamp: Long?, cacheStrategy: CacheStrategy): PreviewUrlData
 
     /**
-     * Clear the cache of all retrieved UrlPreview data
+     * Clear the cache of all retrieved UrlPreview data.
      */
     suspend fun clearCache()
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/PreviewUrlData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/PreviewUrlData.kt
index bfba43a82d2cb8d2e4cb8c1c44b20040d9081f70..b142ad9754a639e9861fca3b6a7c100997203fe3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/PreviewUrlData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/media/PreviewUrlData.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.api.session.media
 
 /**
- * Facility data class to get the common field of a PreviewUrl response form the server
+ * Facility data class to get the common field of a PreviewUrl response form the server.
  *
  * Example of return data for the url `https://matrix.org`:
  * <pre>
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt
index 57aacc98b81a64509699d5707a393c04ca4c3e5a..e8d9c89b547539423f7c8ea9bf48d7726d7b24ea 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt
@@ -33,10 +33,10 @@ sealed class PermalinkData {
             val viaParameters: List<String>
     ) : PermalinkData()
 
-    /**
+    /*
      * &room_name=Team2
-    &room_avatar_url=mxc:
-    &inviter_name=bob
+     * &room_avatar_url=mxc:
+     * &inviter_name=bob
      */
     @Parcelize
     data class RoomEmailInviteLink(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt
index edb748c76ebe9ad8763bce7995a074d07bcd08ac..9d078dc4b243e1f9ff0b5407a22c6f29364e8198 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt
@@ -23,7 +23,7 @@ import timber.log.Timber
 import java.net.URLDecoder
 
 /**
- * This class turns a uri to a [PermalinkData]
+ * This class turns a uri to a [PermalinkData].
  * element-based domains (e.g. https://app.element.io/#/user/@chagai95:matrix.org) permalinks
  * or matrix.to permalinks (e.g. https://matrix.to/#/@chagai95:matrix.org)
  * or client permalinks (e.g. <clientPermalinkBaseUrl>user/@chagai95:matrix.org)
@@ -31,7 +31,7 @@ import java.net.URLDecoder
 object PermalinkParser {
 
     /**
-     * Turns a uri string to a [PermalinkData]
+     * Turns a uri string to a [PermalinkData].
      */
     fun parse(uriString: String): PermalinkData {
         val uri = Uri.parse(uriString)
@@ -39,7 +39,7 @@ object PermalinkParser {
     }
 
     /**
-     * Turns a uri to a [PermalinkData]
+     * Turns a uri to a [PermalinkData].
      * https://github.com/matrix-org/matrix-doc/blob/master/proposals/1704-matrix.to-permalinks.md
      */
     fun parse(uri: Uri): PermalinkData {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt
index c139da813ab75484865f9540314de811e48b718a..b49b80df099c87206773cf54898bc717f97b7c98 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt
@@ -57,7 +57,7 @@ interface PermalinkService {
     fun createPermalink(id: String, forceMatrixTo: Boolean = false): String?
 
     /**
-     * Creates a permalink for a roomId, including the via parameters
+     * Creates a permalink for a roomId, including the via parameters.
      *
      * @param roomId the room id
      * @param forceMatrixTo whether we should force using matrix.to base URL
@@ -79,7 +79,7 @@ interface PermalinkService {
     fun createPermalink(roomId: String, eventId: String, forceMatrixTo: Boolean = false): String
 
     /**
-     * Extract the linked id from the universal link
+     * Extract the linked id from the universal link.
      *
      * @param url the universal link, Ex: "https://matrix.to/#/@benoit:matrix.org"
      * @return the id from the url, ex: "@benoit:matrix.org", or null if the url is not a permalink
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/presence/PresenceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/presence/PresenceService.kt
index 82a81f4b64e064fb61cd0d3536ebc63259349172..901e7ec3dd9ceb577f4322ca91d9a2b3e517a749 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/presence/PresenceService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/presence/PresenceService.kt
@@ -25,7 +25,7 @@ import org.matrix.android.sdk.api.session.presence.model.UserPresence
  */
 interface PresenceService {
     /**
-     * Update the presence status for the current user
+     * Update the presence status for the current user.
      * @param presence the new presence state
      * @param statusMsg the status message to attach to this state
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/presence/model/PresenceEnum.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/presence/model/PresenceEnum.kt
index 6d9994ef1ca9e75b0bde56257e4ba7603f260fbd..c678e2a706b329769e7c4ec69f2ba738c24e92cf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/presence/model/PresenceEnum.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/presence/model/PresenceEnum.kt
@@ -28,7 +28,10 @@ enum class PresenceEnum(val value: String) {
     OFFLINE("offline"),
 
     @Json(name = "unavailable")
-    UNAVAILABLE("unavailable");
+    UNAVAILABLE("unavailable"),
+
+    @Json(name = "org.matrix.msc3026.busy")
+    BUSY("busy");
 
     companion object {
         fun from(s: String): PresenceEnum? = values().find { it.value == s }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt
index d2c677bb31425be809668548914608b3334a425a..095f2ef7c2c9058f463c4b361a73eb05e76fb9fa 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt
@@ -36,21 +36,21 @@ interface ProfileService {
     }
 
     /**
-     * Return the current display name for this user
+     * Return the current display name for this user.
      * @param userId the userId param to look for
      *
      */
     suspend fun getDisplayName(userId: String): Optional<String>
 
     /**
-     * Update the display name for this user
+     * Update the display name for this user.
      * @param userId the userId to update the display name of
      * @param newDisplayName the new display name of the user
      */
     suspend fun setDisplayName(userId: String, newDisplayName: String)
 
     /**
-     * Update the avatar for this user
+     * Update the avatar for this user.
      * @param userId the userId to update the avatar of
      * @param newAvatarUri the new avatar uri of the user
      * @param fileName the fileName of selected image
@@ -74,12 +74,12 @@ interface ProfileService {
     suspend fun getProfile(userId: String): JsonDict
 
     /**
-     * Get the current user 3Pids
+     * Get the current user 3Pids.
      */
     fun getThreePids(): List<ThreePid>
 
     /**
-     * Get the current user 3Pids Live
+     * Get the current user 3Pids Live.
      * @param refreshData set to true to fetch data from the homeserver
      */
     fun getThreePidsLive(refreshData: Boolean): LiveData<List<ThreePid>>
@@ -90,7 +90,7 @@ interface ProfileService {
     fun getPendingThreePids(): List<ThreePid>
 
     /**
-     * Get the pending 3Pids Live
+     * Get the pending 3Pids Live.
      */
     fun getPendingThreePidsLive(): LiveData<List<ThreePid>>
 
@@ -100,18 +100,18 @@ interface ProfileService {
     suspend fun addThreePid(threePid: ThreePid)
 
     /**
-     * Validate a code received by text message
+     * Validate a code received by text message.
      */
     suspend fun submitSmsCode(threePid: ThreePid.Msisdn, code: String)
 
     /**
-     * Finalize adding a 3Pids. Call this method once the user has validated that he owns the ThreePid
+     * Finalize adding a 3Pids. Call this method once the user has validated that he owns the ThreePid.
      */
     suspend fun finalizeAddingThreePid(threePid: ThreePid,
                                        userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor)
 
     /**
-     * Cancel adding a threepid. It will remove locally stored data about this ThreePid
+     * Cancel adding a threepid. It will remove locally stored data about this ThreePid.
      */
     suspend fun cancelAddingThreePid(threePid: ThreePid)
 
@@ -121,7 +121,7 @@ interface ProfileService {
     suspend fun deleteThreePid(threePid: ThreePid)
 
     /**
-     * Return a User object from a userId
+     * Return a User object from a userId.
      */
     suspend fun getProfileAsUser(userId: String): User {
         return getProfile(userId).let { dict ->
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt
index f884d3e8906b8c298d55191254729d41ef363069..5f9857eb2fbb60a19848ead18578bb8ae454675f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt
@@ -21,7 +21,7 @@ import java.util.UUID
 interface PushersService {
 
     /**
-     * Refresh pushers from server state
+     * Refresh pushers from server state.
      */
     fun refreshPushers()
 
@@ -66,7 +66,7 @@ interface PushersService {
                                append: Boolean = true)
 
     /**
-     * Directly ask the push gateway to send a push to this device
+     * Directly ask the push gateway to send a push to this device.
      * If successful, the push gateway has accepted the request. In this case, the app should receive a Push with the provided eventId.
      * In case of error, PusherRejected will be thrown. In this case it means that the pushkey is not valid.
      *
@@ -81,30 +81,30 @@ interface PushersService {
                          eventId: String)
 
     /**
-     * Remove a registered pusher
+     * Remove a registered pusher.
      * @param pusher the pusher to remove, can be http or email
      */
     suspend fun removePusher(pusher: Pusher)
 
     /**
-     * Remove a Http pusher by its pushkey and appId
+     * Remove a Http pusher by its pushkey and appId.
      * @see addHttpPusher
      */
     suspend fun removeHttpPusher(pushkey: String, appId: String)
 
     /**
-     * Remove an Email pusher
+     * Remove an Email pusher.
      * @see addEmailPusher
      */
     suspend fun removeEmailPusher(email: String)
 
     /**
-     * Get the current pushers, as a LiveData
+     * Get the current pushers, as a LiveData.
      */
     fun getPushersLive(): LiveData<List<Pusher>>
 
     /**
-     * Get the current pushers
+     * Get the current pushers.
      */
     fun getPushers(): List<Pusher>
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt
index 7790942d8453bf4655f1dbad1521f36c9c0414a6..2b2930c1ba01022e4352c076647a3563ef1d532e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt
@@ -42,7 +42,7 @@ sealed class Action {
 }
 
 /**
- * Ref: https://matrix.org/docs/spec/client_server/latest#actions
+ * Ref: https://matrix.org/docs/spec/client_server/latest#actions.
  *
  * Convert
  * <pre>
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushRuleService.kt
index abbdbf81049660d2edd0411a0d1b2c5be7329983..bc4860be1153d3aebb783d9d66b2c6aa1650643f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushRuleService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushRuleService.kt
@@ -22,7 +22,7 @@ import org.matrix.android.sdk.api.session.pushrules.rest.RuleSet
 
 interface PushRuleService {
     /**
-     * Fetch the push rules from the server
+     * Fetch the push rules from the server.
      */
     fun fetchPushRules(scope: String = RuleScope.GLOBAL)
 
@@ -33,7 +33,7 @@ interface PushRuleService {
     suspend fun addPushRule(kind: RuleKind, pushRule: PushRule)
 
     /**
-     * Enables/Disables a push rule and updates the actions if necessary
+     * Enables/Disables a push rule and updates the actions if necessary.
      * @param enable Enables/Disables the rule
      * @param actions Actions to update if not null
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushRule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushRule.kt
index 270ffb29408ec9a2699fdb8dc2963b1cf443de0d..a11ffc0a989d1ccaeb06ad1dc57b070c63b60910 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushRule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushRule.kt
@@ -49,7 +49,7 @@ data class PushRule(
         @Json(name = "rule_id")
         val ruleId: String,
         /**
-         * The conditions that must hold true for an event in order for a rule to be applied to an event
+         * The conditions that must hold true for an event in order for a rule to be applied to an event.
          */
         @Json(name = "conditions")
         val conditions: List<PushCondition>? = null,
@@ -71,7 +71,7 @@ data class PushRule(
     }
 
     /**
-     * Set the notification sound
+     * Set the notification sound.
      *
      * @param sound notification sound
      */
@@ -82,7 +82,7 @@ data class PushRule(
     }
 
     /**
-     * Remove the notification sound
+     * Remove the notification sound.
      */
     fun removeNotificationSound(): PushRule {
         return copy(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt
index 1f990f4c0a51cdf083a214e3b72329f9f6e0794e..3a18cf1497ac49f79b228475b0e8ac92c3929cdb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt
@@ -49,18 +49,18 @@ interface Room {
     val coroutineDispatchers: MatrixCoroutineDispatchers
 
     /**
-     * The roomId of this room
+     * The roomId of this room.
      */
     val roomId: String
 
     /**
-     * A live [RoomSummary] associated with the room
+     * A live [RoomSummary] associated with the room.
      * You can observe this summary to get dynamic data from this room.
      */
     fun getRoomSummaryLive(): LiveData<Optional<RoomSummary>>
 
     /**
-     * A current snapshot of [RoomSummary] associated with the room
+     * A current snapshot of [RoomSummary] associated with the room.
      */
     fun roomSummary(): RoomSummary?
 
@@ -70,97 +70,97 @@ interface Room {
     fun asSpace(): Space?
 
     /**
-     * Get the TimelineService associated to this Room
+     * Get the TimelineService associated to this Room.
      */
     fun timelineService(): TimelineService
 
     /**
-     * Get the ThreadsService associated to this Room
+     * Get the ThreadsService associated to this Room.
      */
     fun threadsService(): ThreadsService
 
     /**
-     * Get the ThreadsLocalService associated to this Room
+     * Get the ThreadsLocalService associated to this Room.
      */
     fun threadsLocalService(): ThreadsLocalService
 
     /**
-     * Get the SendService associated to this Room
+     * Get the SendService associated to this Room.
      */
     fun sendService(): SendService
 
     /**
-     * Get the DraftService associated to this Room
+     * Get the DraftService associated to this Room.
      */
     fun draftService(): DraftService
 
     /**
-     * Get the ReadService associated to this Room
+     * Get the ReadService associated to this Room.
      */
     fun readService(): ReadService
 
     /**
-     * Get the TypingService associated to this Room
+     * Get the TypingService associated to this Room.
      */
     fun typingService(): TypingService
 
     /**
-     * Get the AliasService associated to this Room
+     * Get the AliasService associated to this Room.
      */
     fun aliasService(): AliasService
 
     /**
-     * Get the TagsService associated to this Room
+     * Get the TagsService associated to this Room.
      */
     fun tagsService(): TagsService
 
     /**
-     * Get the MembershipService associated to this Room
+     * Get the MembershipService associated to this Room.
      */
     fun membershipService(): MembershipService
 
     /**
-     * Get the StateService associated to this Room
+     * Get the StateService associated to this Room.
      */
     fun stateService(): StateService
 
     /**
-     * Get the UploadsService associated to this Room
+     * Get the UploadsService associated to this Room.
      */
     fun uploadsService(): UploadsService
 
     /**
-     * Get the ReportingService associated to this Room
+     * Get the ReportingService associated to this Room.
      */
     fun reportingService(): ReportingService
 
     /**
-     * Get the RoomCallService associated to this Room
+     * Get the RoomCallService associated to this Room.
      */
     fun roomCallService(): RoomCallService
 
     /**
-     * Get the RelationService associated to this Room
+     * Get the RelationService associated to this Room.
      */
     fun relationService(): RelationService
 
     /**
-     * Get the RoomCryptoService associated to this Room
+     * Get the RoomCryptoService associated to this Room.
      */
     fun roomCryptoService(): RoomCryptoService
 
     /**
-     * Get the RoomPushRuleService associated to this Room
+     * Get the RoomPushRuleService associated to this Room.
      */
     fun roomPushRuleService(): RoomPushRuleService
 
     /**
-     * Get the RoomAccountDataService associated to this Room
+     * Get the RoomAccountDataService associated to this Room.
      */
     fun roomAccountDataService(): RoomAccountDataService
 
     /**
-     * Get the RoomVersionService associated to this Room
+     * Get the RoomVersionService associated to this Room.
      */
     fun roomVersionService(): RoomVersionService
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt
index 9446f0fdffd3033c3fb00e17509c030c67fc673c..cb70603e66cf4c9810b30995b92c055b4bdfc581 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt
@@ -26,18 +26,18 @@ import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsRe
 interface RoomDirectoryService {
 
     /**
-     * Get rooms from directory
+     * Get rooms from directory.
      */
     suspend fun getPublicRooms(server: String?,
                                publicRoomsParams: PublicRoomsParams): PublicRoomsResponse
 
     /**
-     * Get the visibility of a room in the directory
+     * Get the visibility of a room in the directory.
      */
     suspend fun getRoomDirectoryVisibility(roomId: String): RoomDirectoryVisibility
 
     /**
-     * Set the visibility of a room in the directory
+     * Set the visibility of a room in the directory.
      */
     suspend fun setRoomDirectoryVisibility(roomId: String, roomDirectoryVisibility: RoomDirectoryVisibility)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt
index ece9cfbfacf59a77f9f9a7cfc57fb48041f5a6bf..0e631427bd320aefbf516ca120f16b278a31071d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt
@@ -21,13 +21,13 @@ import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 
 /**
- * Get a TimelineEvent using the TimelineService of a Room
+ * Get a TimelineEvent using the TimelineService of a Room.
  */
 fun Room.getTimelineEvent(eventId: String): TimelineEvent? =
         timelineService().getTimelineEvent(eventId)
 
 /**
- * Get a StateEvent using the StateService of a Room
+ * Get a StateEvent using the StateService of a Room.
  */
 fun Room.getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event? =
         stateService().getStateEvent(eventType, stateKey)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt
index 700e292b0c16fc7b26e93c899c73b5f4f270e7aa..6d5551ddf02d43bfe53e872d4eed8201432626b1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt
@@ -36,12 +36,12 @@ import org.matrix.android.sdk.api.util.Optional
 interface RoomService {
 
     /**
-     * Create a room asynchronously
+     * Create a room asynchronously.
      */
     suspend fun createRoom(createRoomParams: CreateRoomParams): String
 
     /**
-     * Create a direct room asynchronously. This is a facility method to create a direct room with the necessary parameters
+     * Create a direct room asynchronously. This is a facility method to create a direct room with the necessary parameters.
      */
     suspend fun createDirectRoom(otherUserId: String): String {
         return createRoom(
@@ -55,7 +55,7 @@ interface RoomService {
     }
 
     /**
-     * Join a room by id
+     * Join a room by id.
      * @param roomIdOrAlias the roomId or the room alias of the room to join
      * @param reason optional reason for joining the room
      * @param viaServers the servers to attempt to join the room through. One of the servers must be participating in the room.
@@ -84,14 +84,14 @@ interface RoomService {
     suspend fun leaveRoom(roomId: String, reason: String? = null)
 
     /**
-     * Get a room from a roomId
+     * Get a room from a roomId.
      * @param roomId the roomId to look for.
      * @return a room with roomId or null
      */
     fun getRoom(roomId: String): Room?
 
     /**
-     * Get a roomSummary from a roomId or a room alias
+     * Get a roomSummary from a roomId or a room alias.
      * @param roomIdOrAlias the roomId or the alias of a room to look for.
      * @return a matching room summary or null
      */
@@ -112,14 +112,14 @@ interface RoomService {
                              sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): LiveData<List<RoomSummary>>
 
     /**
-     * Get a snapshot list of Breadcrumbs
+     * Get a snapshot list of Breadcrumbs.
      * @param queryParams parameters to query the room summaries. It can be use to keep only joined rooms, for instance.
      * @return the immutable list of [RoomSummary]
      */
     fun getBreadcrumbs(queryParams: RoomSummaryQueryParams): List<RoomSummary>
 
     /**
-     * Get a live list of Breadcrumbs
+     * Get a live list of Breadcrumbs.
      * @param queryParams parameters to query the room summaries. It can be use to keep only joined rooms, for instance.
      * @return the [LiveData] of [RoomSummary]
      */
@@ -132,7 +132,7 @@ interface RoomService {
     suspend fun onRoomDisplayed(roomId: String)
 
     /**
-     * Mark all rooms as read
+     * Mark all rooms as read.
      */
     suspend fun markAllAsRead(roomIds: List<String>)
 
@@ -143,7 +143,7 @@ interface RoomService {
                                  searchOnServer: Boolean): Optional<RoomAliasDescription>
 
     /**
-     * Delete a room alias
+     * Delete a room alias.
      */
     suspend fun deleteRoomAlias(roomAlias: String)
 
@@ -162,7 +162,7 @@ interface RoomService {
     fun getChangeMembershipsLive(): LiveData<Map<String, ChangeMembershipState>>
 
     /**
-     * Return the roomId of an existing DM with the other user, or null if such room does not exist
+     * Return the roomId of an existing DM with the other user, or null if such room does not exist.
      * A room is a DM if:
      *  - it is listed in the `m.direct` account data
      *  - the current user has joined the room
@@ -175,7 +175,7 @@ interface RoomService {
     fun getExistingDirectRoomWithUser(otherUserId: String): String?
 
     /**
-     * Get a room member for the tuple {userId,roomId}
+     * Get a room member for the tuple {userId,roomId}.
      * @param userId the userId to look for.
      * @param roomId the roomId to look for.
      * @return the room member or null
@@ -183,7 +183,7 @@ interface RoomService {
     fun getRoomMember(userId: String, roomId: String): RoomMemberSummary?
 
     /**
-     * Observe a live room member for the tuple {userId,roomId}
+     * Observe a live room member for the tuple {userId,roomId}.
      * @param userId the userId to look for.
      * @param roomId the roomId to look for.
      * @return a LiveData of the optional found room member
@@ -191,39 +191,39 @@ interface RoomService {
     fun getRoomMemberLive(userId: String, roomId: String): LiveData<Optional<RoomMemberSummary>>
 
     /**
-     * Get some state events about a room
+     * Get some state events about a room.
      */
     suspend fun getRoomState(roomId: String): List<Event>
 
     /**
-     * Use this if you want to get information from a room that you are not yet in (or invited)
-     * It might be possible to get some information on this room if it is public or if guest access is allowed
-     * This call will try to gather some information on this room, but it could fail and get nothing more
+     * Use this if you want to get information from a room that you are not yet in (or invited).
+     * It might be possible to get some information on this room if it is public or if guest access is allowed.
+     * This call will try to gather some information on this room, but it could fail and get nothing more.
      */
     suspend fun peekRoom(roomIdOrAlias: String): PeekResult
 
     /**
-     * TODO Doc
+     * TODO Doc.
      */
     fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
                                   pagedListConfig: PagedList.Config = defaultPagedListConfig,
                                   sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): LiveData<PagedList<RoomSummary>>
 
     /**
-     * TODO Doc
+     * TODO Doc.
      */
     fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
                                           pagedListConfig: PagedList.Config = defaultPagedListConfig,
                                           sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): UpdatableLivePageResult
 
     /**
-     * Return a LiveData on the number of rooms
+     * Return a LiveData on the number of rooms.
      * @param queryParams parameters to query the room summaries. It can be use to keep only joined rooms, for instance.
      */
     fun getRoomCountLive(queryParams: RoomSummaryQueryParams): LiveData<Int>
 
     /**
-     * TODO Doc
+     * TODO Doc.
      */
     fun getNotificationCountForRooms(queryParams: RoomSummaryQueryParams): RoomAggregateNotificationCount
 
@@ -238,16 +238,16 @@ interface RoomService {
     fun getFlattenRoomSummaryChildrenOf(spaceId: String?, memberships: List<Membership> = Membership.activeMemberships()): List<RoomSummary>
 
     /**
-     * Returns all the children of this space, as LiveData
+     * Returns all the children of this space, as LiveData.
      */
     fun getFlattenRoomSummaryChildrenOfLive(spaceId: String?,
                                             memberships: List<Membership> = Membership.activeMemberships()): LiveData<List<RoomSummary>>
 
     /**
-     * Refreshes the RoomSummary LatestPreviewContent for the given @param roomId
-     * If the roomId is null, all rooms are updated
+     * Refreshes the RoomSummary LatestPreviewContent for the given @param roomId.
+     * If the roomId is null, all rooms are updated.
      *
-     * This is useful for refreshing summary content with encrypted messages after receiving new room keys
+     * This is useful for refreshing summary content with encrypted messages after receiving new room keys.
      */
     fun refreshJoinedRoomSummaryPreviews(roomId: String?)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt
index b4408575187b8ec5d362980ada7d9e0aa135cef4..5c74dcced1be6fe65fdb8024615de874e54cb36a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt
@@ -41,7 +41,7 @@ fun spaceSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) =
 
 /**
  * This class can be used to filter room summaries to use with:
- * [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService]
+ * [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService].
  */
 data class RoomSummaryQueryParams(
         val roomId: QueryStringValue,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataService.kt
index 190749c85cee92957fe16e1729a898d51b0da7f2..b6925dd4a3f47662c2c381c8ae5f7528dad9afff 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/accountdata/RoomAccountDataService.kt
@@ -25,29 +25,29 @@ import org.matrix.android.sdk.api.util.Optional
  */
 interface RoomAccountDataService {
     /**
-     * Retrieve the account data with the provided type or null if not found
+     * Retrieve the account data with the provided type or null if not found.
      */
     fun getAccountDataEvent(type: String): RoomAccountDataEvent?
 
     /**
-     * Observe the account data with the provided type
+     * Observe the account data with the provided type.
      */
     fun getLiveAccountDataEvent(type: String): LiveData<Optional<RoomAccountDataEvent>>
 
     /**
      * Retrieve the account data with the provided types. The return list can have a different size that
      * the size of the types set, because some AccountData may not exist.
-     * If an empty set is provided, all the AccountData are retrieved
+     * If an empty set is provided, all the AccountData are retrieved.
      */
     fun getAccountDataEvents(types: Set<String>): List<RoomAccountDataEvent>
 
     /**
-     * Observe the account data with the provided types. If an empty set is provided, all the AccountData are observed
+     * Observe the account data with the provided types. If an empty set is provided, all the AccountData are observed.
      */
     fun getLiveAccountDataEvents(types: Set<String>): LiveData<List<RoomAccountDataEvent>>
 
     /**
-     * Update the account data with the provided type and the provided account data content
+     * Update the account data with the provided type and the provided account data content.
      */
     suspend fun updateAccountData(type: String, content: Content)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/alias/AliasService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/alias/AliasService.kt
index 5fe7e99425e27b4c6ee1afe3165103bbc6ce83e5..2073db15b30641c34cd7a97b53e7a6135c1a5bc7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/alias/AliasService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/alias/AliasService.kt
@@ -18,13 +18,13 @@ package org.matrix.android.sdk.api.session.room.alias
 
 interface AliasService {
     /**
-     * Get list of local alias of the room
+     * Get list of local alias of the room.
      * @return the list of the aliases (full aliases, not only the local part)
      */
     suspend fun getRoomAliases(): List<String>
 
     /**
-     * Add local alias to the room
+     * Add local alias to the room.
      * @param aliasLocalPart the local part of the alias.
      * Ex: for the alias "#my_alias:example.org", the local part is "my_alias"
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/call/RoomCallService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/call/RoomCallService.kt
index cac5217dd6bd9702ede12dc242cdfc96214c9768..4439253a57a517be17ff58cb4d25562eedf53c8b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/call/RoomCallService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/call/RoomCallService.kt
@@ -21,7 +21,7 @@ package org.matrix.android.sdk.api.session.room.call
  */
 interface RoomCallService {
     /**
-     * Return true if calls (audio or video) can be performed on this Room
+     * Return true if calls (audio or video) can be performed on this Room.
      */
     fun canStartCall(): Boolean
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/members/MembershipService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/members/MembershipService.kt
index 6c8e2d310c0777591f056d223652223635e7941d..e7ac69be74a5f284721b230ae5580d3234465c9c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/members/MembershipService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/members/MembershipService.kt
@@ -39,14 +39,14 @@ interface MembershipService {
     fun getRoomMember(userId: String): RoomMemberSummary?
 
     /**
-     * Return all the roomMembers of the room with params
+     * Return all the roomMembers of the room with params.
      * @param queryParams the params to query for
      * @return a roomMember list.
      */
     fun getRoomMembers(queryParams: RoomMemberQueryParams): List<RoomMemberSummary>
 
     /**
-     * Return all the roomMembers of the room filtered by memberships
+     * Return all the roomMembers of the room filtered by memberships.
      * @param queryParams the params to query for
      * @return a [LiveData] of roomMember list.
      */
@@ -55,27 +55,27 @@ interface MembershipService {
     fun getNumberOfJoinedMembers(): Int
 
     /**
-     * Invite a user in the room
+     * Invite a user in the room.
      */
     suspend fun invite(userId: String, reason: String? = null)
 
     /**
-     * Invite a user with email or phone number in the room
+     * Invite a user with email or phone number in the room.
      */
     suspend fun invite3pid(threePid: ThreePid)
 
     /**
-     * Ban a user from the room
+     * Ban a user from the room.
      */
     suspend fun ban(userId: String, reason: String? = null)
 
     /**
-     * Unban a user from the room
+     * Unban a user from the room.
      */
     suspend fun unban(userId: String, reason: String? = null)
 
     /**
-     * Remove a user from the room
+     * Remove a user from the room.
      */
     suspend fun remove(userId: String, reason: String? = null)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/members/RoomMemberQueryParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/members/RoomMemberQueryParams.kt
index c2c5a7f8045b1e7c2e96a77db0741c0af7a1b5e4..dd83066dbbc7934cac2a423d1851a0ce1d736a15 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/members/RoomMemberQueryParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/members/RoomMemberQueryParams.kt
@@ -24,7 +24,7 @@ fun roomMemberQueryParams(init: (RoomMemberQueryParams.Builder.() -> Unit) = {})
 }
 
 /**
- * This class can be used to filter room members
+ * This class can be used to filter room members.
  */
 data class RoomMemberQueryParams(
         val displayName: QueryStringValue,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/Invite.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/Invite.kt
index 2841da35d12461d5bd3764d1d45dac40c94e2b3c..f3c83c223a522f68ee840dd2067afbe2b5d04ebf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/Invite.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/Invite.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Subclass representing a search API response
+ * Subclass representing a search API response.
  */
 @JsonClass(generateAdapter = true)
 data class Invite(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/Membership.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/Membership.kt
index a5d0f63722c43dc1f110f4de549f76fc0f838dce..c0325d87ec2202a26d11f1a8171d219c68ad0c13 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/Membership.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/Membership.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Represents the membership of a user on a room
+ * Represents the membership of a user on a room.
  */
 @JsonClass(generateAdapter = false)
 enum class Membership {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt
index 5c46db7166efbaadd24479c70e3fee3cd3626e40..8ef94b28968ee2bdf165883166c21702d1b27653 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt
@@ -67,7 +67,7 @@ data class PowerLevelsContent(
         @Json(name = "notifications") val notifications: Map<String, Any>? = null
 ) {
     /**
-     * Return a copy of this content with a new power level for the specified user
+     * Return a copy of this content with a new power level for the specified user.
      *
      * @param userId the userId to alter the power level of
      * @param powerLevel the new power level, or null to set the default value.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/ReferencesAggregatedSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/ReferencesAggregatedSummary.kt
index 49ba2d5ab6a1015d85eef6cc5bd3775bc5a6ed21..0bc87c9bf1927c01c70b5c312ec987e135a3a2f3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/ReferencesAggregatedSummary.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/ReferencesAggregatedSummary.kt
@@ -19,7 +19,7 @@ import org.matrix.android.sdk.api.session.events.model.Content
 
 /**
  * Events can relates to other events, this object keeps a summary
- * of all events that are referencing the 'eventId' event via the RelationType.REFERENCE
+ * of all events that are referencing the 'eventId' event via the RelationType.REFERENCE.
  */
 data class ReferencesAggregatedSummary(
         val content: Content?,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomAvatarContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomAvatarContent.kt
index 8c1c9e6b1213ebae256cd8f623016353e9cb828e..b6567fcf2117905a2a1e822705c3a3a3a6fcfecc 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomAvatarContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomAvatarContent.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing the EventType.STATE_ROOM_AVATAR state event content
+ * Class representing the EventType.STATE_ROOM_AVATAR state event content.
  */
 @JsonClass(generateAdapter = true)
 data class RoomAvatarContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomCanonicalAliasContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomCanonicalAliasContent.kt
index 4e8bd2e71b4335371a931ae609a98292950883f6..1e76bef6f3e60adc41f2519dbb6915d54b7e3011 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomCanonicalAliasContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomCanonicalAliasContent.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing the EventType.STATE_ROOM_CANONICAL_ALIAS state event content
+ * Class representing the EventType.STATE_ROOM_CANONICAL_ALIAS state event content.
  */
 @JsonClass(generateAdapter = true)
 data class RoomCanonicalAliasContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomGuestAccessContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomGuestAccessContent.kt
index 020e7ed39e50c6c40400bb2025ccdffc19e63de4..ba274325bc5b4ff67789a4245c7766886bb5e0cb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomGuestAccessContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomGuestAccessContent.kt
@@ -27,13 +27,13 @@ import timber.log.Timber
 @JsonClass(generateAdapter = true)
 data class RoomGuestAccessContent(
         // Required. Whether guests can join the room. One of: ["can_join", "forbidden"]
-        @Json(name = "guest_access") val _guestAccess: String? = null
+        @Json(name = "guest_access") val guestAccessStr: String? = null
 ) {
-    val guestAccess: GuestAccess? = when (_guestAccess) {
+    val guestAccess: GuestAccess? = when (guestAccessStr) {
         "can_join"  -> GuestAccess.CanJoin
         "forbidden" -> GuestAccess.Forbidden
         else        -> {
-            Timber.w("Invalid value for GuestAccess: `$_guestAccess`")
+            Timber.w("Invalid value for GuestAccess: `$guestAccessStr`")
             null
         }
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibilityContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibilityContent.kt
index 3ac14e48de77e592e05fcb75ed80b6ce371e4423..da5c90ff0534f955b4b30e1fa37c3dfee9b21d32 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibilityContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibilityContent.kt
@@ -22,15 +22,15 @@ import timber.log.Timber
 
 @JsonClass(generateAdapter = true)
 data class RoomHistoryVisibilityContent(
-        @Json(name = "history_visibility") val _historyVisibility: String? = null
+        @Json(name = "history_visibility") val historyVisibilityStr: String? = null
 ) {
-    val historyVisibility: RoomHistoryVisibility? = when (_historyVisibility) {
+    val historyVisibility: RoomHistoryVisibility? = when (historyVisibilityStr) {
         "world_readable" -> RoomHistoryVisibility.WORLD_READABLE
         "shared"         -> RoomHistoryVisibility.SHARED
         "invited"        -> RoomHistoryVisibility.INVITED
         "joined"         -> RoomHistoryVisibility.JOINED
         else             -> {
-            Timber.w("Invalid value for RoomHistoryVisibility: `$_historyVisibility`")
+            Timber.w("Invalid value for RoomHistoryVisibility: `$historyVisibilityStr`")
             null
         }
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesContent.kt
index 5237b10d52b3cbd8d9edcdb85309029ad7caa8e9..3b338a36cd0056ee4ad5628c9c8342cf8df59da9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesContent.kt
@@ -23,11 +23,11 @@ import com.squareup.moshi.JsonClass
 import timber.log.Timber
 
 /**
- * Class representing the EventType.STATE_ROOM_JOIN_RULES state event content
+ * Class representing the EventType.STATE_ROOM_JOIN_RULES state event content.
  */
 @JsonClass(generateAdapter = true)
 data class RoomJoinRulesContent(
-        @Json(name = "join_rule") val _joinRules: String? = null,
+        @Json(name = "join_rule") val joinRulesStr: String? = null,
         /**
          * If the allow key is an empty list (or not a list at all),
          * then no users are allowed to join without an invite.
@@ -35,14 +35,14 @@ data class RoomJoinRulesContent(
          */
         @Json(name = "allow") val allowList: List<RoomJoinRulesAllowEntry>? = null
 ) {
-    val joinRules: RoomJoinRules? = when (_joinRules) {
+    val joinRules: RoomJoinRules? = when (joinRulesStr) {
         "public"     -> RoomJoinRules.PUBLIC
         "invite"     -> RoomJoinRules.INVITE
         "knock"      -> RoomJoinRules.KNOCK
         "private"    -> RoomJoinRules.PRIVATE
         "restricted" -> RoomJoinRules.RESTRICTED
         else         -> {
-            Timber.w("Invalid value for RoomJoinRules: `$_joinRules`")
+            Timber.w("Invalid value for RoomJoinRules: `$joinRulesStr`")
             null
         }
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomMemberContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomMemberContent.kt
index f29dd6a3e55c02087a8f72014bb4ae360bfb03e8..2529edbfdd9c80481a302c423f18f77caf7df92c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomMemberContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomMemberContent.kt
@@ -21,7 +21,7 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.api.session.events.model.UnsignedData
 
 /**
- * Class representing the EventType.STATE_ROOM_MEMBER state event content
+ * Class representing the EventType.STATE_ROOM_MEMBER state event content.
  */
 @JsonClass(generateAdapter = true)
 data class RoomMemberContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomMemberSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomMemberSummary.kt
index 39177a4296b8983dcb5b8e66e5e1c7531e05b9ac..8e7382190a3f7ce692a3399c4448afe9480168f1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomMemberSummary.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomMemberSummary.kt
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.session.room.model
 import org.matrix.android.sdk.api.session.presence.model.UserPresence
 
 /**
- * Class representing a simplified version of EventType.STATE_ROOM_MEMBER state event content
+ * Class representing a simplified version of EventType.STATE_ROOM_MEMBER state event content.
  */
 data class RoomMemberSummary constructor(
         val membership: Membership,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomNameContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomNameContent.kt
index a0b45e881b5ae33065857086b0c0327bab1180f0..2dbb5f9e5736414b8a60fc79be625ada02b6f078 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomNameContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomNameContent.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing the EventType.STATE_ROOM_NAME state event content
+ * Class representing the EventType.STATE_ROOM_NAME state event content.
  */
 @JsonClass(generateAdapter = true)
 data class RoomNameContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomStrippedState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomStrippedState.kt
index dc0c00b282c93efc6958c12fff0f7abecca88d89..b4f663f8010cde6d3309ac3ef2fd54c5c3c51555 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomStrippedState.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomStrippedState.kt
@@ -79,7 +79,7 @@ data class RoomStrippedState(
         val avatarUrl: String? = null,
 
         /**
-         * Undocumented item
+         * Undocumented item.
          */
         @Json(name = "m.federate")
         val isFederated: Boolean = false,
@@ -103,7 +103,7 @@ data class RoomStrippedState(
         val membership: String?
 ) {
     /**
-     * Return the canonical alias, or the first alias from the list of aliases, or null
+     * Return the canonical alias, or the first alias from the list of aliases, or null.
      */
     fun getPrimaryAlias(): String? {
         return canonicalAlias ?: aliases?.firstOrNull()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomTopicContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomTopicContent.kt
index b97ee44dee8b5cfa01b2ed538c797d4185c6517c..18092f12ac4283218835f4e7ffa4bebf7d91e38a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomTopicContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomTopicContent.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing the EventType.STATE_ROOM_TOPIC state event content
+ * Class representing the EventType.STATE_ROOM_TOPIC state event content.
  */
 @JsonClass(generateAdapter = true)
 data class RoomTopicContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallCapabilities.kt
index d911ca3b88927bd8b5f6608019d83d1af0cedff7..6937b2c2e4275c156fe9e1630828f42913248dd9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallCapabilities.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallCapabilities.kt
@@ -24,7 +24,7 @@ import org.matrix.android.sdk.api.extensions.orFalse
 data class CallCapabilities(
         /**
          * If set to true, states that the sender of the event supports the m.call.replaces event and therefore supports
-         * being transferred to another destination
+         * being transferred to another destination.
          */
         @Json(name = "m.call.transferee") val transferee: Boolean? = null
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallInviteContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallInviteContent.kt
index 24c8152f3cca195faa00c3ada52b74688ea5665f..40038ab8ec55cb4b910ecb924c982a1a3d7600e6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallInviteContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallInviteContent.kt
@@ -47,7 +47,7 @@ data class CallInviteContent(
          */
         @Json(name = "lifetime") val lifetime: Int?,
         /**
-         * The field should be added for all invites where the target is a specific user
+         * The field should be added for all invites where the target is a specific user.
          */
         @Json(name = "invitee") val invitee: String? = null,
         /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallReplacesContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallReplacesContent.kt
index e480e013ea9ced4c49dffe7029a3a6a0dddbc719..849fa50537e6eb75d244002b93641d3442d13dfc 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallReplacesContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallReplacesContent.kt
@@ -44,7 +44,7 @@ data class CallReplacesContent(
          */
         @Json(name = "target_room") val targetRoomId: String? = null,
         /**
-         * An object giving information about the transfer target
+         * An object giving information about the transfer target.
          */
         @Json(name = "target_user") val targetUser: TargetUser? = null,
         /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt
index ce1e0e0d144493ab328ee054673f05ff6bac54f2..b7b0cc890b382f2f33598250623d26b5f49820ae 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt
@@ -69,13 +69,13 @@ open class CreateRoomParams {
     val invite3pids = mutableListOf<ThreePid>()
 
     /**
-     * Initial Guest Access
+     * Initial Guest Access.
      */
     var guestAccess: GuestAccess? = null
 
     /**
      * If set to true, when the room will be created, if cross-signing is enabled and we can get keys for every invited users,
-     * the encryption will be enabled on the created room
+     * the encryption will be enabled on the created room.
      */
     var enableEncryptionIfInvitedUsersSupportIt: Boolean = false
 
@@ -135,7 +135,7 @@ open class CreateRoomParams {
         }
 
     /**
-     * The power level content to override in the default power level event
+     * The power level content to override in the default power level event.
      */
     var powerLevelContentOverride: PowerLevelsContent? = null
 
@@ -148,7 +148,7 @@ open class CreateRoomParams {
     }
 
     /**
-     * Supported value: MXCRYPTO_ALGORITHM_MEGOLM
+     * Supported value: MXCRYPTO_ALGORITHM_MEGOLM.
      */
     var algorithm: String? = null
         private set
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/Predecessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/Predecessor.kt
index f48beb299aeb7cc2a53a20b77c57f9e0c4555091..99c829b0e24c8ee67b7e07f27c6e0520684a5fc8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/Predecessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/Predecessor.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * A link to an old room in case of room versioning
+ * A link to an old room in case of room versioning.
  */
 @JsonClass(generateAdapter = true)
 data class Predecessor(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomCreateContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomCreateContent.kt
index 52e5c0e9c7f67081934570e0aa22b1fd6b523f3a..d73c941a863cf9b318444eb71f5d2b9d3ce95428 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomCreateContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomCreateContent.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Content of a m.room.create type event
+ * Content of a m.room.create type event.
  */
 @JsonClass(generateAdapter = true)
 data class RoomCreateContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomFeaturePreset.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomFeaturePreset.kt
index f5f722d7833059eaa3d2d81d00f287249df0641b..6487ad947fa18356c5c6b9d3893ec080a4468170 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomFeaturePreset.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/RoomFeaturePreset.kt
@@ -47,7 +47,7 @@ class RestrictedRoomPreset(val homeServerCapabilities: HomeServerCapabilities, v
                         type = EventType.STATE_ROOM_JOIN_RULES,
                         stateKey = "",
                         content = RoomJoinRulesContent(
-                                _joinRules = RoomJoinRules.RESTRICTED.value,
+                                joinRulesStr = RoomJoinRules.RESTRICTED.value,
                                 allowList = restrictedList
                         ).toContent()
                 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/FileInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/FileInfo.kt
index 132b72902f5e9de2c397fc6ded5c29ce468ad25f..ae786ff7062915f86a95f40df071966540be80f2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/FileInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/FileInfo.kt
@@ -49,7 +49,7 @@ data class FileInfo(
 )
 
 /**
- * Get the url of the encrypted thumbnail or of the thumbnail
+ * Get the url of the encrypted thumbnail or of the thumbnail.
  */
 fun FileInfo.getThumbnailUrl(): String? {
     return thumbnailFile?.url ?: thumbnailUrl
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/ImageInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/ImageInfo.kt
index bd99ea690019b9ba428f5bf0d96376226e553eaa..ec6669d4ec36dbf3843620d71ecbe2eeb1f22cf2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/ImageInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/ImageInfo.kt
@@ -59,7 +59,7 @@ data class ImageInfo(
 )
 
 /**
- * Get the url of the encrypted thumbnail or of the thumbnail
+ * Get the url of the encrypted thumbnail or of the thumbnail.
  */
 fun ImageInfo.getThumbnailUrl(): String? {
     return thumbnailFile?.url ?: thumbnailUrl
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconInfoContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconInfoContent.kt
index f75704a89158b704dca114a22b13439c1ee1b8b0..f8b627e497549325636119f5dba9a59dc5f357a4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconInfoContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconInfoContent.kt
@@ -32,7 +32,7 @@ import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultCon
 @JsonClass(generateAdapter = true)
 data class MessageBeaconInfoContent(
         /**
-         * Local message type, not from server
+         * Local message type, not from server.
          */
         @Transient
         override val msgType: String = MessageType.MSGTYPE_BEACON_INFO,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconLocationDataContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconLocationDataContent.kt
index 4a4ef46bc84b583d8050a0db242c8983469e3216..e261ab52066495786445e215d852e2d85e3fc7a6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconLocationDataContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageBeaconLocationDataContent.kt
@@ -32,7 +32,7 @@ import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultCon
 @JsonClass(generateAdapter = true)
 data class MessageBeaconLocationDataContent(
         /**
-         * Local message type, not from server
+         * Local message type, not from server.
          */
         @Transient
         override val msgType: String = MessageType.MSGTYPE_BEACON_LOCATION_DATA,
@@ -42,13 +42,13 @@ data class MessageBeaconLocationDataContent(
         @Json(name = "m.new_content") override val newContent: Content? = null,
 
         /**
-         * See [MSC3488](https://github.com/matrix-org/matrix-doc/blob/matthew/location/proposals/3488-location.md)
+         * See [MSC3488](https://github.com/matrix-org/matrix-doc/blob/matthew/location/proposals/3488-location.md).
          */
         @Json(name = "org.matrix.msc3488.location") val unstableLocationInfo: LocationInfo? = null,
         @Json(name = "m.location") val locationInfo: LocationInfo? = null,
 
         /**
-         * Exact time that the data in the event refers to (milliseconds since the UNIX epoch)
+         * Exact time that the data in the event refers to (milliseconds since the UNIX epoch).
          */
         @Json(name = "org.matrix.msc3488.ts") val unstableTimestampMillis: Long? = null,
         @Json(name = "m.ts") val timestampMillis: Long? = null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageContentWithFormattedBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageContentWithFormattedBody.kt
index aabf6173d7ecee0b7896cd6e1d53a7b3f367f5b6..58ea8db02dfd216d3b9cedd0f27193e2171ba3bf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageContentWithFormattedBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageContentWithFormattedBody.kt
@@ -28,7 +28,7 @@ interface MessageContentWithFormattedBody : MessageContent {
     val formattedBody: String?
 
     /**
-     * Get the formattedBody, only if not blank and if the format is equal to "org.matrix.custom.html"
+     * Get the formattedBody, only if not blank and if the format is equal to "org.matrix.custom.html".
      */
     val matrixFormattedBody: String?
         get() = formattedBody?.takeIf { it.isNotBlank() && format == MessageFormat.FORMAT_MATRIX_HTML }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageEndPollContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageEndPollContent.kt
index 491b71477e472619bdef14faf08b14c98cb9b432..f0511903d0fec26aae24d136229b2cb2e54ec278 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageEndPollContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageEndPollContent.kt
@@ -21,7 +21,7 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
 
 /**
- * Class representing the org.matrix.msc3381.poll.end event content
+ * Class representing the org.matrix.msc3381.poll.end event content.
  */
 @JsonClass(generateAdapter = true)
 data class MessageEndPollContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageImageInfoContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageImageInfoContent.kt
index 369a1a1a46937d2effdeb30bcd326b84e69e5b70..e2b69eff333294e7c4c3ab184e5f9670d9c3efda 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageImageInfoContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageImageInfoContent.kt
@@ -18,7 +18,7 @@
 package org.matrix.android.sdk.api.session.room.model.message
 
 /**
- * A content with image information
+ * A content with image information.
  */
 interface MessageImageInfoContent : MessageWithAttachmentContent {
     val info: ImageInfo?
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLocationContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLocationContent.kt
index 19cb20430d2968b3d3cad8f7f28f95c3be00f113..0a66a6e400d5b3a75a7549ad15863890d379dd71 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLocationContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageLocationContent.kt
@@ -42,12 +42,12 @@ data class MessageLocationContent(
         @Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
         @Json(name = "m.new_content") override val newContent: Content? = null,
         /**
-         * See [MSC3488](https://github.com/matrix-org/matrix-doc/blob/matthew/location/proposals/3488-location.md)
+         * See [MSC3488](https://github.com/matrix-org/matrix-doc/blob/matthew/location/proposals/3488-location.md).
          */
         @Json(name = "org.matrix.msc3488.location") val unstableLocationInfo: LocationInfo? = null,
         @Json(name = "m.location") val locationInfo: LocationInfo? = null,
         /**
-         * Exact time that the data in the event refers to (milliseconds since the UNIX epoch)
+         * Exact time that the data in the event refers to (milliseconds since the UNIX epoch).
          */
         @Json(name = "org.matrix.msc3488.ts") val unstableTimestampMillis: Long? = null,
         @Json(name = "m.ts") val timestampMillis: Long? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessagePollContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessagePollContent.kt
index 43c0c9006818342e9c4f531936df68299eba1688..f784f052839a03e1d2a59a3626b261e1d41980c4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessagePollContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessagePollContent.kt
@@ -24,7 +24,7 @@ import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultCon
 @JsonClass(generateAdapter = true)
 data class MessagePollContent(
         /**
-         * Local message type, not from server
+         * Local message type, not from server.
          */
         @Transient
         override val msgType: String = MessageType.MSGTYPE_POLL_START,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessagePollResponseContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessagePollResponseContent.kt
index 022915ed695d1a4cc1d88c4447f57333d0b436b3..32bfb710907df748b41287a8a2aebf5d138f9185 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessagePollResponseContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessagePollResponseContent.kt
@@ -24,7 +24,7 @@ import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultCon
 @JsonClass(generateAdapter = true)
 data class MessagePollResponseContent(
         /**
-         * Local message type, not from server
+         * Local message type, not from server.
          */
         @Transient
         override val msgType: String = MessageType.MSGTYPE_POLL_RESPONSE,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageStickerContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageStickerContent.kt
index 3d774cadb292591d62e137a0827be277b5d49932..f8c1c0d79876b99b83e7f11ed930d9c0c6528511 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageStickerContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageStickerContent.kt
@@ -25,7 +25,7 @@ import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultCon
 @JsonClass(generateAdapter = true)
 data class MessageStickerContent(
         /**
-         * Set in local, not from server
+         * Set in local, not from server.
          */
         @Transient
         override val msgType: String = MessageType.MSGTYPE_STICKER_LOCAL,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVerificationKeyContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVerificationKeyContent.kt
index 1a15e056abe3e0ef1b7bb9d398739b401ad45ac4..a6b36ce6cb6ff53b8d8a0fde2e9743724a290f33 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVerificationKeyContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVerificationKeyContent.kt
@@ -26,7 +26,7 @@ import org.matrix.android.sdk.internal.crypto.verification.VerificationInfoKeyFa
 @JsonClass(generateAdapter = true)
 internal data class MessageVerificationKeyContent(
         /**
-         * The device’s ephemeral public key, as an unpadded base64 string
+         * The device’s ephemeral public key, as an unpadded base64 string.
          */
         @Json(name = "key") override val key: String? = null,
         @Json(name = "m.relates_to") val relatesTo: RelationDefaultContent?
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageWithAttachmentContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageWithAttachmentContent.kt
index 95dfb6b8648be044e0ce439768176fe56cc85511..8d9dbee6b3ddbf5fc6c4e9f08953cab5ddf3ecd1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageWithAttachmentContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageWithAttachmentContent.kt
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.session.room.model.message
 import org.matrix.android.sdk.api.session.crypto.model.EncryptedFileInfo
 
 /**
- * Interface for message which can contains an encrypted file
+ * Interface for message which can contains an encrypted file.
  */
 interface MessageWithAttachmentContent : MessageContent {
     /**
@@ -36,7 +36,7 @@ interface MessageWithAttachmentContent : MessageContent {
 }
 
 /**
- * Get the url of the encrypted file or of the file
+ * Get the url of the encrypted file or of the file.
  */
 fun MessageWithAttachmentContent.getFileUrl() = encryptedFileInfo?.url ?: url
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/VideoInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/VideoInfo.kt
index b02b4d96adc7696ffe8ca16d54f02e4a375ad636..b9c2472197c2523136aba4620ccd0623916bf6b9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/VideoInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/VideoInfo.kt
@@ -64,7 +64,7 @@ data class VideoInfo(
 )
 
 /**
- * Get the url of the encrypted thumbnail or of the thumbnail
+ * Get the url of the encrypted thumbnail or of the thumbnail.
  */
 fun VideoInfo.getThumbnailUrl(): String? {
     return thumbnailFile?.url ?: thumbnailUrl
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationContent.kt
index 53b1fea873d5b43dd936a7b88c74dd528e9246b0..01f7425322b2471ff280655155f24d931b95a8d2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationContent.kt
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.session.room.model.relation
 import org.matrix.android.sdk.api.session.events.model.RelationType
 
 interface RelationContent {
-    /** See [RelationType] for known possible values */
+    /** See [RelationType] for known possible values. */
     val type: String?
     val eventId: String?
     val inReplyTo: ReplyToContent?
@@ -27,7 +27,7 @@ interface RelationContent {
 
     /**
      * This flag indicates that the message should be rendered as a reply
-     * fallback, when isFallingBack = false
+     * fallback, when isFallingBack = false.
      */
     val isFallingBack: Boolean?
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt
index 44098989084eb4d43435fc9f65960a93bd7ab0e4..0d094b835b3066a61df8299a46b7f9eea5c9074c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt
@@ -82,7 +82,7 @@ interface RelationService {
                  options: List<String>): Cancelable
 
     /**
-     * Edit a text message body. Limited to "m.text" contentType
+     * Edit a text message body. Limited to "m.text" contentType.
      * @param targetEvent The event to edit
      * @param newBodyText The edited body
      * @param compatibilityBodyText The text that will appear on clients that don't support yet edition
@@ -107,7 +107,7 @@ interface RelationService {
                   compatibilityBodyText: String = "* $newBodyText"): Cancelable
 
     /**
-     * Get the edit history of the given event
+     * Get the edit history of the given event.
      * The return list will contain the original event and all the editions of this event, done by the
      * same sender, sorted in the reverse order (so the original event is the latest element, and the
      * latest edition is the first element of the list)
@@ -133,21 +133,21 @@ interface RelationService {
     ): Cancelable?
 
     /**
-     * Get the current EventAnnotationsSummary
+     * Get the current EventAnnotationsSummary.
      * @param eventId the eventId to look for EventAnnotationsSummary
      * @return the EventAnnotationsSummary found
      */
     fun getEventAnnotationsSummary(eventId: String): EventAnnotationsSummary?
 
     /**
-     * Get a LiveData of EventAnnotationsSummary for the specified eventId
+     * Get a LiveData of EventAnnotationsSummary for the specified eventId.
      * @param eventId the eventId to look for EventAnnotationsSummary
      * @return the LiveData of EventAnnotationsSummary
      */
     fun getEventAnnotationsSummaryLive(eventId: String): LiveData<Optional<EventAnnotationsSummary>>
 
     /**
-     * Creates a thread reply for an existing timeline event
+     * Creates a thread reply for an existing timeline event.
      * The replyInThreadText can be a Spannable and contains special spans (MatrixItemSpan) that will be translated
      * by the sdk into pills.
      * @param rootThreadEventId the root thread eventId
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoom.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoom.kt
index 01f5d9cde86dcc68a21068e8f9cfd91e1647115b..2033f366ae3361ac4adda0643fb7a6567614554e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoom.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoom.kt
@@ -79,13 +79,13 @@ data class PublicRoom(
         val avatarUrl: String? = null,
 
         /**
-         * Undocumented item
+         * Undocumented item.
          */
         @Json(name = "m.federate")
         val isFederated: Boolean = false
 ) {
     /**
-     * Return the canonical alias, or the first alias from the list of aliases, or null
+     * Return the canonical alias, or the first alias from the list of aliases, or null.
      */
     fun getPrimaryAlias(): String? {
         return canonicalAlias ?: aliases?.firstOrNull()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoomsFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoomsFilter.kt
index 66ebc59464abc6043a9cf0966af5db259dbd37c0..cc0ce669b9658a0f21f1bc1cf73bd5e0145210d4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoomsFilter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoomsFilter.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class to define a filter to retrieve public rooms
+ * Class to define a filter to retrieve public rooms.
  */
 @JsonClass(generateAdapter = true)
 data class PublicRoomsFilter(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoomsParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoomsParams.kt
index 3af354a01dff8753dd8aa9d78c689f53779f9a35..c4227b5767f2117e640d1399ea98c1b9b23103c9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoomsParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoomsParams.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class to pass parameters to get the public rooms list
+ * Class to pass parameters to get the public rooms list.
  */
 @JsonClass(generateAdapter = true)
 data class PublicRoomsParams(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoomsResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoomsResponse.kt
index 82da8bc49bc385a1d49df48a407ec85c499150a7..5a33ba3cdf63d9337c6afc39e9cc427a299de4f2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoomsResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/roomdirectory/PublicRoomsResponse.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing the public rooms request response
+ * Class representing the public rooms request response.
  */
 @JsonClass(generateAdapter = true)
 data class PublicRoomsResponse(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/thirdparty/ThirdPartyProtocolInstance.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/thirdparty/ThirdPartyProtocolInstance.kt
index 0ca04445898c86a57cdc0af4a3e84fd0f8af29c6..6a2dc4765009c12264c39ef9a0220d34569341cb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/thirdparty/ThirdPartyProtocolInstance.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/thirdparty/ThirdPartyProtocolInstance.kt
@@ -46,13 +46,13 @@ data class ThirdPartyProtocolInstance(
         val networkId: String? = null,
 
         /**
-         * FIXDOC Not documented on matrix.org doc
+         * FIXDOC Not documented on matrix.org doc.
          */
         @Json(name = "instance_id")
         val instanceId: String? = null,
 
         /**
-         * FIXDOC Not documented on matrix.org doc
+         * FIXDOC Not documented on matrix.org doc.
          */
         @Json(name = "bot_user_id")
         val botUserId: String? = null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/tombstone/RoomTombstoneContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/tombstone/RoomTombstoneContent.kt
index 9b607aa712c85406d5ce53ad5c1328c6d8f155d3..d0a976cd97fefff5f910a73ad94e692946cea08d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/tombstone/RoomTombstoneContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/tombstone/RoomTombstoneContent.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class to contains Tombstone information
+ * Class to contains Tombstone information.
  */
 @JsonClass(generateAdapter = true)
 data class RoomTombstoneContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/notification/RoomNotificationState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/notification/RoomNotificationState.kt
index ea59ff4d4899fecb1a33107f2f02055d2efd8905..919aed63eb906cfbee5e0e2d05c90d80ef2a8b93 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/notification/RoomNotificationState.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/notification/RoomNotificationState.kt
@@ -17,26 +17,26 @@
 package org.matrix.android.sdk.api.session.room.notification
 
 /**
- * Defines the room notification state
+ * Defines the room notification state.
  */
 enum class RoomNotificationState {
     /**
-     * All the messages will trigger a noisy notification
+     * All the messages will trigger a noisy notification.
      */
     ALL_MESSAGES_NOISY,
 
     /**
-     * All the messages will trigger a notification
+     * All the messages will trigger a notification.
      */
     ALL_MESSAGES,
 
     /**
-     * Only the messages with user display name / user name will trigger notifications
+     * Only the messages with user display name / user name will trigger notifications.
      */
     MENTIONS_ONLY,
 
     /**
-     * No notifications
+     * No notifications.
      */
     MUTE
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt
index 99139723a82f15ce874d337f9b667fb653ccc47e..165a912b7fac0ed9898d38a45abf872b92938500 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt
@@ -32,7 +32,7 @@ import org.matrix.android.sdk.api.session.room.model.usersDefaultOrDefault
 class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
 
     /**
-     * Returns the user power level of a dedicated user Id
+     * Returns the user power level of a dedicated user Id.
      *
      * @param userId the user id
      * @return the power level
@@ -44,7 +44,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
     }
 
     /**
-     * Returns the user power level of a dedicated user Id
+     * Returns the user power level of a dedicated user Id.
      *
      * @param userId the user id
      * @return the power level
@@ -56,7 +56,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
     }
 
     /**
-     * Tell if an user can send an event of a certain type
+     * Tell if an user can send an event of a certain type.
      *
      * @param userId  the id of the user to check for.
      * @param isState true if the event is a state event (ie. state key is not null)
@@ -77,7 +77,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
     }
 
     /**
-     * Check if the user have the necessary power level to invite
+     * Check if the user have the necessary power level to invite.
      * @param userId the id of the user to check for.
      * @return true if able to invite
      */
@@ -87,7 +87,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
     }
 
     /**
-     * Check if the user have the necessary power level to ban
+     * Check if the user have the necessary power level to ban.
      * @param userId the id of the user to check for.
      * @return true if able to ban
      */
@@ -97,7 +97,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
     }
 
     /**
-     * Check if the user have the necessary power level to kick
+     * Check if the user have the necessary power level to kick (remove).
      * @param userId the id of the user to check for.
      * @return true if able to kick
      */
@@ -107,7 +107,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
     }
 
     /**
-     * Check if the user have the necessary power level to redact
+     * Check if the user have the necessary power level to redact.
      * @param userId the id of the user to check for.
      * @return true if able to redact
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/read/ReadService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/read/ReadService.kt
index b037a3f3668846b4b6f54e9bbe99b2c9fe573cee..036628c02f53151ce68f2f9fdad1529ecb509539 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/read/ReadService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/read/ReadService.kt
@@ -62,7 +62,7 @@ interface ReadService {
     fun getMyReadReceiptLive(): LiveData<Optional<String>>
 
     /**
-     * Get the eventId where the read receipt for the provided user is
+     * Get the eventId where the read receipt for the provided user is.
      * @param userId the id of the user to look for
      *
      * @return the eventId where the read receipt for the provided user is attached, or null if not found
@@ -70,7 +70,7 @@ interface ReadService {
     fun getUserReadReceipt(userId: String): String?
 
     /**
-     * Returns a live list of read receipts for a given event
+     * Returns a live list of read receipts for a given event.
      * @param eventId: the event
      */
     fun getEventReadReceiptsLive(eventId: String): LiveData<List<ReadReceipt>>
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/DraftService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/DraftService.kt
index a9481d71a2002ce3873cf840e5999681fafaa0bd..e03c89a12a6930d7fea27851632d24cd83dea6dc 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/DraftService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/DraftService.kt
@@ -22,22 +22,22 @@ import org.matrix.android.sdk.api.util.Optional
 interface DraftService {
 
     /**
-     * Save or update a draft to the room
+     * Save or update a draft to the room.
      */
     suspend fun saveDraft(draft: UserDraft)
 
     /**
-     * Delete the last draft, basically just after sending the message
+     * Delete the last draft, basically just after sending the message.
      */
     suspend fun deleteDraft()
 
     /**
-     * Return the current draft or null
+     * Return the current draft or null.
      */
     fun getDraft(): UserDraft?
 
     /**
-     * Return the current draft if any, as a live data
+     * Return the current draft if any, as a live data.
      */
     fun getDraftLive(): LiveData<Optional<UserDraft>>
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt
index af7ab11df13452e52a9cf7ca9560e862dae3a6b5..4bb8abef8aaaff9c1b2292b10857a8799de9e4a5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt
@@ -126,19 +126,19 @@ interface SendService {
     fun redactEvent(event: Event, reason: String?): Cancelable
 
     /**
-     * Schedule this message to be resent
+     * Schedule this message to be resent.
      * @param localEcho the unsent local echo
      */
     fun resendTextMessage(localEcho: TimelineEvent): Cancelable
 
     /**
-     * Schedule this message to be resent
+     * Schedule this message to be resent.
      * @param localEcho the unsent local echo
      */
     fun resendMediaMessage(localEcho: TimelineEvent): Cancelable
 
     /**
-     * Send a location event to the room
+     * Send a location event to the room.
      * @param latitude required latitude of the location
      * @param longitude required longitude of the location
      * @param uncertainty Accuracy of the location in meters
@@ -156,23 +156,23 @@ interface SendService {
     fun sendLiveLocation(beaconInfoEventId: String, latitude: Double, longitude: Double, uncertainty: Double?): Cancelable
 
     /**
-     * Remove this failed message from the timeline
+     * Remove this failed message from the timeline.
      * @param localEcho the unsent local echo
      */
     fun deleteFailedEcho(localEcho: TimelineEvent)
 
     /**
-     * Cancel sending a specific event. It has to be in one of the sending states
+     * Cancel sending a specific event. It has to be in one of the sending states.
      */
     fun cancelSend(eventId: String)
 
     /**
-     * Resend all failed messages one by one (and keep order)
+     * Resend all failed messages one by one (and keep order).
      */
     fun resendAllFailedMessages()
 
     /**
-     * Cancel all failed messages
+     * Cancel all failed messages.
      */
     fun cancelAllFailedMessages()
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/UserDraft.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/UserDraft.kt
index a8c0de2fa50916659c5897b37c6236ec8caf3681..4ede1a66fc53a755917f0a493c16037fad70f400 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/UserDraft.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/UserDraft.kt
@@ -21,7 +21,7 @@ package org.matrix.android.sdk.api.session.room.send
  * REGULAR: draft of a classical message
  * QUOTE: draft of a message which quotes another message
  * EDIT: draft of an edition of a message
- * REPLY: draft of a reply of another message
+ * REPLY: draft of a reply of another message.
  */
 sealed interface UserDraft {
     data class Regular(val content: String) : UserDraft
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/sender/SenderInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/sender/SenderInfo.kt
index 9b73136fc3792237b77013c38a776ccedc349f49..4c308c355a02163f30f533fb221c027b85364a47 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/sender/SenderInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/sender/SenderInfo.kt
@@ -21,7 +21,7 @@ import org.matrix.android.sdk.internal.util.replaceSpaceChars
 data class SenderInfo(
         val userId: String,
         /**
-         * Consider using [disambiguatedDisplayName]
+         * Consider using [disambiguatedDisplayName].
          */
         val displayName: String?,
         val isUniqueDisplayName: Boolean,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt
index 98171795e2cb30307f80af2d7d63aaaa730217f7..f6b56128d39aa8782e254550b8ecfc0d52f4b3f9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt
@@ -30,57 +30,57 @@ import org.matrix.android.sdk.api.util.Optional
 interface StateService {
 
     /**
-     * Update the topic of the room
+     * Update the topic of the room.
      */
     suspend fun updateTopic(topic: String)
 
     /**
-     * Update the name of the room
+     * Update the name of the room.
      */
     suspend fun updateName(name: String)
 
     /**
-     * Update the canonical alias of the room
+     * Update the canonical alias of the room.
      * @param alias the canonical alias, or null to reset the canonical alias of this room
      * @param altAliases the alternative aliases for this room. It should include the canonical alias if any.
      */
     suspend fun updateCanonicalAlias(alias: String?, altAliases: List<String>)
 
     /**
-     * Update the history readability of the room
+     * Update the history readability of the room.
      */
     suspend fun updateHistoryReadability(readability: RoomHistoryVisibility)
 
     /**
-     * Update the join rule and/or the guest access
+     * Update the join rule and/or the guest access.
      */
     suspend fun updateJoinRule(joinRules: RoomJoinRules?, guestAccess: GuestAccess?, allowList: List<RoomJoinRulesAllowEntry>? = null)
 
     /**
-     * Update the avatar of the room
+     * Update the avatar of the room.
      */
     suspend fun updateAvatar(avatarUri: Uri, fileName: String)
 
     /**
-     * Delete the avatar of the room
+     * Delete the avatar of the room.
      */
     suspend fun deleteAvatar()
 
     /**
-     * Stops sharing live location in the room
+     * Stops sharing live location in the room.
      * @param userId user id
      */
     suspend fun stopLiveLocation(userId: String)
 
     /**
-     * Returns beacon info state event of a user
+     * Returns beacon info state event of a user.
      * @param userId user id who is sharing location
      * @param filterOnlyLive filters only ongoing live location sharing beacons if true else ended event is included
      */
     suspend fun getLiveLocationBeaconInfo(userId: String, filterOnlyLive: Boolean): Event?
 
     /**
-     * Send a state event to the room
+     * Send a state event to the room.
      * @param eventType The type of event to send.
      * @param stateKey The state_key for the state to send. Can be an empty string.
      * @param body The content object of the event; the fields in this object will vary depending on the type of event
@@ -89,23 +89,23 @@ interface StateService {
     suspend fun sendStateEvent(eventType: String, stateKey: String, body: JsonDict): String
 
     /**
-     * Get a state event of the room
+     * Get a state event of the room.
      */
     fun getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event?
 
     /**
-     * Get a live state event of the room
+     * Get a live state event of the room.
      */
     fun getStateEventLive(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): LiveData<Optional<Event>>
 
     /**
-     * Get state events of the room
+     * Get state events of the room.
      * @param eventTypes Set of eventType. If empty, all state events will be returned
      */
     fun getStateEvents(eventTypes: Set<String>, stateKey: QueryStringValue = QueryStringValue.NoCondition): List<Event>
 
     /**
-     * Get live state events of the room
+     * Get live state events of the room.
      * @param eventTypes Set of eventType to observe. If empty, all state events will be observed
      */
     fun getStateEventsLive(eventTypes: Set<String>, stateKey: QueryStringValue = QueryStringValue.NoCondition): LiveData<List<Event>>
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateServiceExtension.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateServiceExtension.kt
index c625a7f0885196a70085fab71ab14a2cceb61a35..9e45fc126dbad4b82ddc4c3c8b011229c86d7ecc 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateServiceExtension.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateServiceExtension.kt
@@ -23,7 +23,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
 import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
 
 /**
- * Return true if a room can be joined by anyone (RoomJoinRules.PUBLIC)
+ * Return true if a room can be joined by anyone (RoomJoinRules.PUBLIC).
  */
 fun StateService.isPublic(): Boolean {
     return getStateEvent(EventType.STATE_ROOM_JOIN_RULES, QueryStringValue.NoCondition)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/tags/TagsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/tags/TagsService.kt
index 69fde61f90e44e142db07663d91ecfb04c289248..b6b82d84047b29a8839cb582a8ef7282d3b5c03c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/tags/TagsService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/tags/TagsService.kt
@@ -21,12 +21,12 @@ package org.matrix.android.sdk.api.session.room.tags
  */
 interface TagsService {
     /**
-     * Add a tag to a room
+     * Add a tag to a room.
      */
     suspend fun addTag(tag: String, order: Double?)
 
     /**
-     * Remove tag from a room
+     * Remove tag from a room.
      */
     suspend fun deleteTag(tag: String)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/ThreadsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/ThreadsService.kt
index 839cdff63badd9cb2052cb615e2ffec14f5d1875..9587be68f124f9129c29a86cef866158408d6085 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/ThreadsService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/ThreadsService.kt
@@ -28,24 +28,24 @@ import org.matrix.android.sdk.api.session.room.threads.model.ThreadSummary
 interface ThreadsService {
 
     /**
-     * Returns a [LiveData] list of all the [ThreadSummary] that exists at the room level
+     * Returns a [LiveData] list of all the [ThreadSummary] that exists at the room level.
      */
     fun getAllThreadSummariesLive(): LiveData<List<ThreadSummary>>
 
     /**
-     * Returns a list of all the [ThreadSummary] that exists at the room level
+     * Returns a list of all the [ThreadSummary] that exists at the room level.
      */
     fun getAllThreadSummaries(): List<ThreadSummary>
 
     /**
      * Enhance the provided ThreadSummary[List] by adding the latest
-     * message edition for that thread
+     * message edition for that thread.
      * @return the enhanced [List] with edited updates
      */
     fun enhanceThreadWithEditions(threads: List<ThreadSummary>): List<ThreadSummary>
 
     /**
-     * Fetch all thread replies for the specified thread using the /relations api
+     * Fetch all thread replies for the specified thread using the /relations api.
      * @param rootThreadEventId the root thread eventId
      * @param from defines the token that will fetch from that position
      * @param limit defines the number of max results the api will respond with
@@ -53,7 +53,7 @@ interface ThreadsService {
     suspend fun fetchThreadTimeline(rootThreadEventId: String, from: String, limit: Int)
 
     /**
-     * Fetch all thread summaries for the current room using the enhanced /messages api
+     * Fetch all thread summaries for the current room using the enhanced /messages api.
      */
     suspend fun fetchThreadSummaries()
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/local/ThreadsLocalService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/local/ThreadsLocalService.kt
index f7b379e3821b04d1a920b993139b0a647c8a6757..b5cef3c62ba89ecfe2130a943237eb353c615719 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/local/ThreadsLocalService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/local/ThreadsLocalService.kt
@@ -27,34 +27,34 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 interface ThreadsLocalService {
 
     /**
-     * Returns a [LiveData] list of all the thread root TimelineEvents that exists at the room level
+     * Returns a [LiveData] list of all the thread root TimelineEvents that exists at the room level.
      */
     fun getAllThreadsLive(): LiveData<List<TimelineEvent>>
 
     /**
-     * Returns a list of all the thread root TimelineEvents that exists at the room level
+     * Returns a list of all the thread root TimelineEvents that exists at the room level.
      */
     fun getAllThreads(): List<TimelineEvent>
 
     /**
-     * Returns a [LiveData] list of all the marked unread threads that exists at the room level
+     * Returns a [LiveData] list of all the marked unread threads that exists at the room level.
      */
     fun getMarkedThreadNotificationsLive(): LiveData<List<TimelineEvent>>
 
     /**
-     * Returns a list of all the marked unread threads that exists at the room level
+     * Returns a list of all the marked unread threads that exists at the room level.
      */
     fun getMarkedThreadNotifications(): List<TimelineEvent>
 
     /**
-     * Returns whether or not the current user is participating in the thread
-     * @param rootThreadEventId the eventId of the current thread
+     * Returns whether or not the current user is participating in the thread.
+     * @param rootThreadEventId the eventId of the current thread.
      */
     fun isUserParticipatingInThread(rootThreadEventId: String): Boolean
 
     /**
      * Enhance the provided root thread TimelineEvent [List] by adding the latest
-     * message edition for that thread
+     * message edition for that thread.
      * @return the enhanced [List] with edited updates
      */
     fun mapEventsWithEdition(threads: List<TimelineEvent>): List<TimelineEvent>
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadSummary.kt
index 017afba1baebee3b169a672542515b4ea55a81b8..1ef972e889be030601c086df4d0ecff7a5249839 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadSummary.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadSummary.kt
@@ -20,7 +20,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.room.sender.SenderInfo
 
 /**
- * The main thread Summary model, mainly used to display the thread list
+ * The main thread Summary model, mainly used to display the thread list.
  */
 data class ThreadSummary(val roomId: String,
                          val rootEvent: Event?,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/Timeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/Timeline.kt
index d47a656798c45df853a592c8f04f6370d28f1bd2..1824d5dc6c587b950ce28bbf9aa0ebc9f6e0fec8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/Timeline.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/Timeline.kt
@@ -100,23 +100,23 @@ interface Timeline {
         fun onTimelineUpdated(snapshot: List<TimelineEvent>) = Unit
 
         /**
-         * Called whenever an error we can't recover from occurred
+         * Called whenever an error we can't recover from occurred.
          */
         fun onTimelineFailure(throwable: Throwable) = Unit
 
         /**
-         * Called when new events come through the sync
+         * Called when new events come through the sync.
          */
         fun onNewTimelineEvents(eventIds: List<String>) = Unit
 
         /**
-         * Called when the pagination state has changed in one direction
+         * Called when the pagination state has changed in one direction.
          */
         fun onStateUpdated(direction: Direction, state: PaginationState) = Unit
     }
 
     /**
-     * Pagination state
+     * Pagination state.
      */
     data class PaginationState(
             val hasMoreToLoad: Boolean = true,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt
index adbc8ab12a02ea8c1aa8196dde983a20d84abf11..b87bc25435cc249858ca133f763d2cce042e5c0c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt
@@ -47,7 +47,7 @@ import org.matrix.android.sdk.api.util.ContentUtils.extractUsefulTextFromReply
 data class TimelineEvent(
         val root: Event,
         /**
-         * Uniquely identify an event, computed locally by the sdk
+         * Uniquely identify an event, computed locally by the sdk.
          */
         val localId: Long,
         val eventId: String,
@@ -103,12 +103,12 @@ data class TimelineEvent(
 }
 
 /**
- * Tells if the event has been edited
+ * Tells if the event has been edited.
  */
 fun TimelineEvent.hasBeenEdited() = annotations?.editSummary != null
 
 /**
- * Get the latest known eventId for an edited event, or the eventId for an Event which has not been edited
+ * Get the latest known eventId for an edited event, or the eventId for an Event which has not been edited.
  */
 fun TimelineEvent.getLatestEventId(): String {
     return annotations
@@ -119,21 +119,21 @@ fun TimelineEvent.getLatestEventId(): String {
 }
 
 /**
- * Get the relation content if any
+ * Get the relation content if any.
  */
 fun TimelineEvent.getRelationContent(): RelationDefaultContent? {
     return root.getRelationContent()
 }
 
 /**
- * Get the eventId which was edited by this event if any
+ * Get the eventId which was edited by this event if any.
  */
 fun TimelineEvent.getEditedEventId(): String? {
     return getRelationContent()?.takeIf { it.type == RelationType.REPLACE }?.eventId
 }
 
 /**
- * Get last MessageContent, after a possible edition
+ * Get last MessageContent, after a possible edition.
  */
 fun TimelineEvent.getLastMessageContent(): MessageContent? {
     return when (root.getClearType()) {
@@ -145,7 +145,7 @@ fun TimelineEvent.getLastMessageContent(): MessageContent? {
 }
 
 /**
- * Returns true if it's a reply
+ * Returns true if it's a reply.
  */
 fun TimelineEvent.isReply(): Boolean {
     return root.isReply()
@@ -163,14 +163,14 @@ fun TimelineEvent.isSticker(): Boolean {
 }
 
 /**
- * Returns whether or not the event is a root thread event
+ * Returns whether or not the event is a root thread event.
  */
 fun TimelineEvent.isRootThread(): Boolean {
     return root.threadDetails?.isRootThread.orFalse()
 }
 
 /**
- * Get the latest message body, after a possible edition, stripping the reply prefix if necessary
+ * Get the latest message body, after a possible edition, stripping the reply prefix if necessary.
  */
 fun TimelineEvent.getTextEditableContent(): String {
     val lastContentBody = getLastMessageContent()?.body ?: return ""
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt
index a35a291d9b2342f385447efb167da54c221d3080..0f0c15b61382c3c8076aad49c26ebe0fbe80cfdb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEventFilters.kt
@@ -19,19 +19,19 @@ package org.matrix.android.sdk.api.session.room.timeline
 // TODO Move to internal, strange?
 data class TimelineEventFilters(
         /**
-         * A flag to filter edit events
+         * A flag to filter edit events.
          */
         val filterEdits: Boolean = false,
         /**
-         * A flag to filter redacted events
+         * A flag to filter redacted events.
          */
         val filterRedacted: Boolean = false,
         /**
-         * A flag to filter useless events, such as membership events without any change
+         * A flag to filter useless events, such as membership events without any change.
          */
         val filterUseless: Boolean = false,
         /**
-         * A flag to filter by types. It should be used with [allowedTypes] field
+         * A flag to filter by types. It should be used with [allowedTypes] field.
          */
         val filterTypes: Boolean = false,
         /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineSettings.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineSettings.kt
index b45f3ecb71f5ff6ff90de643c6f9bdf93e1ad7ae..fd6732d0d13bbbcf2cec79fe4e5efa230e147cd0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineSettings.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineSettings.kt
@@ -29,13 +29,17 @@ data class TimelineSettings(
          */
         val buildReadReceipts: Boolean = true,
         /**
-         * The root thread eventId if this is a thread timeline, or null if this is NOT a thread timeline
+         * The root thread eventId if this is a thread timeline, or null if this is NOT a thread timeline.
          */
         val rootThreadEventId: String? = null,
+        /**
+         * If true Sender Info shown in room will get the latest data information (avatar + displayName).
+         */
+        val useLiveSenderInfo: Boolean = false,
 ) {
 
     /**
-     * Returns true if this is a thread timeline or false otherwise
+     * Returns true if this is a thread timeline or false otherwise.
      */
     fun isThreadTimeline() = rootThreadEventId != null
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/typing/TypingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/typing/TypingService.kt
index e69afa4fc8eb6740fdef34111f675915a81ed4b4..a462d5cba7fd864566ddca8de3e365aa44ebcf1b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/typing/TypingService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/typing/TypingService.kt
@@ -22,7 +22,7 @@ package org.matrix.android.sdk.api.session.room.typing
 interface TypingService {
 
     /**
-     * To call when user is typing a message in the room
+     * To call when user is typing a message in the room.
      * The SDK will handle the requests scheduling to the homeserver:
      * - No more than one typing request per 10s
      * - If not called after 10s, the SDK will notify the homeserver that the user is not typing anymore
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/uploads/UploadsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/uploads/UploadsService.kt
index e2462d007d26109e38110147b56f3a7d43c32c97..b6fec9cd51232cee4c91df7d5e9d88f354590ee4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/uploads/UploadsService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/uploads/UploadsService.kt
@@ -22,7 +22,7 @@ package org.matrix.android.sdk.api.session.room.uploads
 interface UploadsService {
 
     /**
-     * Get a list of events containing URL sent to a room, from most recent to oldest one
+     * Get a list of events containing URL sent to a room, from most recent to oldest one.
      * @param numberOfEvents the expected number of events to retrieve. The result can contain less events.
      * @param since token to get next page, or null to get the first page
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt
index d806e6007e55ff82c0c911ac9e41b27b5cc846d6..4b6c907af01a9ae07d210288a2522ae45de9fcbb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/version/RoomVersionService.kt
@@ -18,28 +18,28 @@ package org.matrix.android.sdk.api.session.room.version
 
 interface RoomVersionService {
     /**
-     * Return the room version of this room
+     * Return the room version of this room.
      */
     fun getRoomVersion(): String
 
     /**
-     * Upgrade to the given room version
+     * Upgrade to the given room version.
      * @return the replacement room id
      */
     suspend fun upgradeToVersion(version: String): String
 
     /**
-     * Get the recommended room version for the current homeserver
+     * Get the recommended room version for the current homeserver.
      */
     fun getRecommendedVersion(): String
 
     /**
-     * Ask if the user has enough power level to upgrade the room
+     * Ask if the user has enough power level to upgrade the room.
      */
     fun userMayUpgradeRoom(userId: String): Boolean
 
     /**
-     * Return true if the current room version is declared unstable by the homeserver
+     * Return true if the current room version is declared unstable by the homeserver.
      */
     fun isUsingUnstableRoomVersion(): Boolean
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/EncryptedSecretContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/EncryptedSecretContent.kt
index 42682efb12b0344031764fa524b62af773305d1a..ddcecb466c385ae5422c732deae28b8bd60a753f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/EncryptedSecretContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/EncryptedSecretContent.kt
@@ -29,7 +29,7 @@ import org.matrix.android.sdk.internal.session.user.accountdata.AccountDataConte
  */
 @JsonClass(generateAdapter = true)
 data class EncryptedSecretContent(
-        /** unpadded base64-encoded ciphertext */
+        /** unpadded base64-encoded ciphertext. */
         @Json(name = "ciphertext") val ciphertext: String? = null,
         @Json(name = "mac") val mac: String? = null,
         @Json(name = "ephemeral") val ephemeral: String? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SecretStorageKeyContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SecretStorageKeyContent.kt
index f7725be00725fbffc657e9cc185358d7a8a78692..e7f872e40054986934aba245ff2d672cb76ff4ce 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SecretStorageKeyContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SecretStorageKeyContent.kt
@@ -51,7 +51,7 @@ data class KeyInfo(
 
 @JsonClass(generateAdapter = true)
 data class SecretStorageKeyContent(
-        /** Currently support m.secret_storage.v1.curve25519-aes-sha2 */
+        /** Currently support m.secret_storage.v1.curve25519-aes-sha2. */
         @Json(name = "algorithm") val algorithm: String? = null,
         @Json(name = "name") val name: String? = null,
         @Json(name = "passphrase") val passphrase: SsssPassphrase? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SharedSecretStorageService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SharedSecretStorageService.kt
index 721a2bc8af11f03577ac931014bdf1f869fbcb8c..528e07196693656b73440350bd77f8795c01b0b7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SharedSecretStorageService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SharedSecretStorageService.kt
@@ -98,12 +98,12 @@ interface SharedSecretStorageService {
     suspend fun storeSecret(name: String, secretBase64: String, keys: List<KeyRef>)
 
     /**
-     * Use this call to determine which SSSSKeySpec to use for requesting secret
+     * Use this call to determine which SSSSKeySpec to use for requesting secret.
      */
     fun getAlgorithmsForSecret(name: String): List<KeyInfoResult>
 
     /**
-     * Get an encrypted secret from the shared storage
+     * Get an encrypted secret from the shared storage.
      *
      * @param name The name of the secret
      * @param keyId The id of the key that should be used to decrypt (null for default key)
@@ -113,7 +113,7 @@ interface SharedSecretStorageService {
     suspend fun getSecret(name: String, keyId: String?, secretKey: SsssKeySpec): String
 
     /**
-     * Return true if SSSS is configured
+     * Return true if SSSS is configured.
      */
     fun isRecoverySetup(): Boolean {
         return checkShouldBeAbleToAccessSecrets(
@@ -131,7 +131,7 @@ interface SharedSecretStorageService {
 
     fun checkShouldBeAbleToAccessSecrets(secretNames: List<String>, keyId: String?): IntegrityResult
 
-    fun requestSecret(name: String, myOtherDeviceId: String)
+    suspend fun requestSecret(name: String, myOtherDeviceId: String)
 
     data class KeyRef(
             val keyId: String?,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SsssKeySpec.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SsssKeySpec.kt
index 03efb9b3dbbbd4fca28b6a41491524db113cc32e..35a67b086578214d6af5cbae7600d9bc7fcf1603 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SsssKeySpec.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SsssKeySpec.kt
@@ -20,7 +20,7 @@ import org.matrix.android.sdk.api.listeners.ProgressListener
 import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromRecoveryKey
 import org.matrix.android.sdk.internal.crypto.keysbackup.deriveKey
 
-/** Tag class */
+/** Tag class. */
 interface SsssKeySpec
 
 data class RawBytesKeySpec(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/signout/SignOutService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/signout/SignOutService.kt
index 4e4eba274e242cf076907dbe1c3db8d8385578fd..d64b2e6e92d71cb233054960a493255b955842e2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/signout/SignOutService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/signout/SignOutService.kt
@@ -30,12 +30,12 @@ interface SignOutService {
     suspend fun signInAgain(password: String)
 
     /**
-     * Update the session with credentials received after SSO
+     * Update the session with credentials received after SSO.
      */
     suspend fun updateCredentials(credentials: Credentials)
 
     /**
-     * Sign out, and release the session, clear all the session data, including crypto data
+     * Sign out, and release the session, clear all the session data, including crypto data.
      * @param signOutFromHomeserver true if the sign out request has to be done
      */
     suspend fun signOut(signOutFromHomeserver: Boolean)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/JoinSpaceResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/JoinSpaceResult.kt
index e8c69977c6a59c510a04129e975869f8bffa904f..a8a7ec61d7cad1a108f5dea06bda5615d8855e88 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/JoinSpaceResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/JoinSpaceResult.kt
@@ -20,7 +20,7 @@ sealed class JoinSpaceResult {
     object Success : JoinSpaceResult()
     data class Fail(val error: Throwable) : JoinSpaceResult()
 
-    /** Success fully joined the space, but failed to join all or some of it's rooms */
+    /** Success fully joined the space, but failed to join all or some of it's rooms. */
     data class PartialSuccess(val failedRooms: Map<String, Throwable>) : JoinSpaceResult()
 
     fun isSuccess() = this is Success || this is PartialSuccess
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt
index f0ed9daac5dc651cace526cb13484736e84e7eff..c9903886285c8349e396fa784bccd311cbe31a31 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt
@@ -27,7 +27,7 @@ interface Space {
     val spaceId: String
 
     /**
-     * A current snapshot of [RoomSummary] associated with the space
+     * A current snapshot of [RoomSummary] associated with the space.
      */
     fun spaceSummary(): RoomSummary?
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt
index afd26f7be54e10d545732d2131dc54a3d267556d..8f16b3b9c3fb7c711403af61b1feb9c67bbc341e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt
@@ -29,13 +29,13 @@ typealias SpaceSummaryQueryParams = RoomSummaryQueryParams
 interface SpaceService {
 
     /**
-     * Create a space asynchronously
+     * Create a space asynchronously.
      * @return the spaceId of the created space
      */
     suspend fun createSpace(params: CreateSpaceParams): String
 
     /**
-     * Just a shortcut for space creation for ease of use
+     * Just a shortcut for space creation for ease of use.
      */
     suspend fun createSpace(name: String,
                             topic: String?,
@@ -44,7 +44,7 @@ interface SpaceService {
                             roomAliasLocalPart: String? = null): String
 
     /**
-     * Get a space from a roomId
+     * Get a space from a roomId.
      * @param spaceId the roomId to look for.
      * @return a space with spaceId or null if room type is not space
      */
@@ -58,7 +58,7 @@ interface SpaceService {
     suspend fun peekSpace(spaceId: String): SpacePeekResult
 
     /**
-     * Get's information of a space by querying the server
+     * Get's information of a space by querying the server.
      * @param suggestedOnly If true, return only child events and rooms where the m.space.child event has suggested: true.
      * @param limit a client-defined limit to the maximum number of rooms to return per page. Must be a non-negative integer.
      * @param from: Optional. Pagination token given to retrieve the next set of rooms. Note that if a pagination token is provided,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceChildContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceChildContent.kt
index b55f90cef06ba4ab7cf6260b508eead7ed6989b2..215fcd9a54267228f6f087f34ab33c089a12f392 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceChildContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceChildContent.kt
@@ -20,11 +20,14 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
+ * Example:
+ * <pre>
  *  "content": {
  *      "via": ["example.com"],
  *      "order": "abcd",
  *      "default": true
  *  }
+ * </pre>.
  */
 @JsonClass(generateAdapter = true)
 data class SpaceChildContent(
@@ -56,7 +59,7 @@ data class SpaceChildContent(
 ) {
     /**
      * Orders which are not strings, or do not consist solely of ascii characters in the range \x20 (space) to \x7F (~),
-     * or consist of more than 50 characters, are forbidden and should be ignored if received.)
+     * or consist of more than 50 characters, are forbidden and should be ignored if received.).
      */
     fun validOrder(): String? {
         return order
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceOrderContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceOrderContent.kt
index a8578347c87de3d05f0a5d7619175e08fa14b880..47e276414ec6f9c7600cb9242bedf0140f270fd5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceOrderContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/model/SpaceOrderContent.kt
@@ -20,12 +20,15 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.api.MatrixPatterns
 
 /**
+ * Example:
+ * <pre>
  * {
  * "type": "m.space_order",
  *   "content": {
  *       "order": "..."
  *   }
  * }
+ * </pre>.
  */
 @JsonClass(generateAdapter = true)
 data class SpaceOrderContent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/statistics/StatisticEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/statistics/StatisticEvent.kt
index 946792d31ef8731417fa377959b751983f4f8273..76755517ce25546e14c201be3880e94eb9e96b46 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/statistics/StatisticEvent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/statistics/StatisticEvent.kt
@@ -17,11 +17,11 @@
 package org.matrix.android.sdk.api.session.statistics
 
 /**
- * Statistic Events. You can subscribe to received such events using [Session.Listener]
+ * Statistic Events. You can subscribe to received such events using [Session.Listener].
  */
 sealed interface StatisticEvent {
     /**
-     * Initial sync request, response downloading, and treatment (parsing and storage) of response
+     * Initial sync request, response downloading, and treatment (parsing and storage) of response.
      */
     data class InitialSyncRequest(val requestDurationMs: Int,
                                   val downloadDurationMs: Int,
@@ -29,7 +29,7 @@ sealed interface StatisticEvent {
                                   val nbOfJoinedRooms: Int) : StatisticEvent
 
     /**
-     * Incremental sync event
+     * Incremental sync event.
      */
     data class SyncTreatment(val durationMs: Int,
                              val afterPause: Boolean,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/FilterService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/FilterService.kt
index 6d1d12f1bc68857d84cfea3951a4449e3f4982ee..bc592df47407b5b22969335172803409cc1c1aa1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/FilterService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/FilterService.kt
@@ -22,13 +22,13 @@ interface FilterService {
         NoFilter,
 
         /**
-         * Filter for Element, will include only known event type
+         * Filter for Element, will include only known event type.
          */
         ElementFilter
     }
 
     /**
-     * Configure the filter for the sync
+     * Configure the filter for the sync.
      */
     fun setFilter(filterPreset: FilterPreset)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStrategy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStrategy.kt
index 461d816ea7ca34f91f53cf46595d40eab5d5f8f6..11f1093393969c642953bf7e4b08ef491908f03b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStrategy.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStrategy.kt
@@ -20,7 +20,7 @@ var initialSyncStrategy: InitialSyncStrategy = InitialSyncStrategy.Optimized()
 
 sealed class InitialSyncStrategy {
     /**
-     * Parse the result in its entirety
+     * Parse the result in its entirety.
      * Pros:
      * - Faster to handle parsed data
      * Cons:
@@ -32,21 +32,21 @@ sealed class InitialSyncStrategy {
 
     /**
      * Optimized.
-     * First store the request result in a file, to avoid doing it again in case of crash
+     * First store the request result in a file, to avoid doing it again in case of crash.
      */
     data class Optimized(
             /**
-             * Limit to reach to decide to split the init sync response into smaller files
-             * Empiric value: 1 megabytes
+             * Limit to reach to decide to split the init sync response into smaller files.
+             * Empiric value: 1 megabytes.
              */
             val minSizeToSplit: Long = 1_048_576, // 1024 * 1024
             /**
-             * Limit per room to reach to decide to store a join room ephemeral Events into a file
-             * Empiric value: 1 kilobytes
+             * Limit per room to reach to decide to store a join room ephemeral Events into a file.
+             * Empiric value: 1 kilobytes.
              */
             val minSizeToStoreInFile: Long = 1024,
             /**
-             * Max number of rooms to insert at a time in database (to avoid too much RAM usage)
+             * Max number of rooms to insert at a time in database (to avoid too much RAM usage).
              */
             val maxRoomsToInsert: Int = 100
     ) : InitialSyncStrategy()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/DeviceListResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/DeviceListResponse.kt
index c05e1e51878ea37d5a4fe3c540e107d020d11a91..929343e45d0ec4ec4be6cd52812f15b228ffbb75 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/DeviceListResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/DeviceListResponse.kt
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.session.sync.model
 import com.squareup.moshi.JsonClass
 
 /**
- * This class describes the device list response from a sync request
+ * This class describes the device list response from a sync request.
  */
 @JsonClass(generateAdapter = true)
 data class DeviceListResponse(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/LazyRoomSyncEphemeral.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/LazyRoomSyncEphemeral.kt
index 087a5f52dc5977913519ac7f67328bde96be97cb..5bd7719d0146379fc1949dfeab755c82c74abf79 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/LazyRoomSyncEphemeral.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/LazyRoomSyncEphemeral.kt
@@ -20,6 +20,6 @@ import com.squareup.moshi.JsonClass
 
 @JsonClass(generateAdapter = false)
 sealed class LazyRoomSyncEphemeral {
-    data class Parsed(val _roomSyncEphemeral: RoomSyncEphemeral) : LazyRoomSyncEphemeral()
+    data class Parsed(val roomSyncEphemeral: RoomSyncEphemeral) : LazyRoomSyncEphemeral()
     object Stored : LazyRoomSyncEphemeral()
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSync.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSync.kt
index e3d07602c7955f4c0eb894f90c345a0450df6f8b..e5ac0a39b234710e8cf206aa750c7449efbdfe8d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSync.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSync.kt
@@ -48,7 +48,7 @@ data class RoomSync(
         @Json(name = "unread_notifications") val unreadNotifications: RoomSyncUnreadNotifications? = null,
 
         /**
-         * The room summary
+         * The room summary.
          */
         @Json(name = "summary") val summary: RoomSyncSummary? = null
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncSummary.kt
index 7216a0c992f4f7e564513b0347d104490489dc67..050fa119bb7953f7b2f05fea229e2cbe5683154b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncSummary.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncSummary.kt
@@ -36,12 +36,12 @@ data class RoomSyncSummary(
         @Json(name = "m.heroes") val heroes: List<String> = emptyList(),
 
         /**
-         * The number of m.room.members in state 'joined' (including the syncing user) (can be null)
+         * The number of m.room.members in state 'joined' (including the syncing user) (can be null).
          */
         @Json(name = "m.joined_member_count") val joinedMembersCount: Int? = null,
 
         /**
-         * The number of m.room.members in state 'invited' (can be null)
+         * The number of m.room.members in state 'invited' (can be null).
          */
         @Json(name = "m.invited_member_count") val invitedMembersCount: Int? = null
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncTimeline.kt
index 82d29a52e2ff6ada48c240d8b72fd7d0fbf58329..4fc8adb7696326f762d46d4c5a2979cad0900384 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncTimeline.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncTimeline.kt
@@ -30,12 +30,12 @@ data class RoomSyncTimeline(
         @Json(name = "events") val events: List<Event>? = null,
 
         /**
-         * Boolean which tells whether there are more events on the server
+         * Boolean which tells whether there are more events on the server.
          */
         @Json(name = "limited") val limited: Boolean = false,
 
         /**
-         * If the batch was limited then this is a token that can be supplied to the server to retrieve more events
+         * If the batch was limited then this is a token that can be supplied to the server to retrieve more events.
          */
         @Json(name = "prev_batch") val prevToken: String? = null
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/SyncResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/SyncResponse.kt
index d7dff72288f8ad64d513f3ac5b7e336f2e63b85a..c70964a513e3e5c361e4b2571a0cb37689657ee5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/SyncResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/SyncResponse.kt
@@ -48,12 +48,12 @@ data class SyncResponse(
         @Json(name = "rooms") val rooms: RoomsSyncResponse? = null,
 
         /**
-         * Devices list update
+         * Devices list update.
          */
         @Json(name = "device_lists") val deviceLists: DeviceListResponse? = null,
 
         /**
-         * One time keys management
+         * One time keys management.
          */
         @Json(name = "device_one_time_keys_count")
         val deviceOneTimeKeysCount: DeviceOneTimeKeysCountSyncResponse? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadNotificationBadgeState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadNotificationBadgeState.kt
index 8e861e73de1a279946c35d68aa8e7aab00ba3655..f3e92ad84315b4e12164ccaa292b8cd320e583f1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadNotificationBadgeState.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadNotificationBadgeState.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.api.session.threads
 
 /**
- * This class defines the state of a thread notification badge
+ * This class defines the state of a thread notification badge.
  */
 data class ThreadNotificationBadgeState(
         val numberOfLocalUnreadThreads: Int = 0,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadNotificationState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadNotificationState.kt
index 8566d68aa52ab389dd4a89f9d6678e110fc795ba..c110802d23a77d4463efe2fd459da3e81c196e1a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadNotificationState.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadNotificationState.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.api.session.threads
 
 /**
- * This class defines the state of a thread notification
+ * This class defines the state of a thread notification.
  */
 enum class ThreadNotificationState {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadTimelineEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadTimelineEvent.kt
index 7b433566b8df2029f6a112e52ef121ab76a6ef07..53f89cefab6fa635c03dadb6f513a918d18c1822 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadTimelineEvent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadTimelineEvent.kt
@@ -20,7 +20,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 
 /**
  * This class contains a thread TimelineEvent along with a boolean that
- * determines if the current user has participated in that event
+ * determines if the current user has participated in that event.
  */
 data class ThreadTimelineEvent(
         val timelineEvent: TimelineEvent,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/UserService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/UserService.kt
index 063abdb5a0d3e1d6474f8c1569c00481a3ef8918..0c5465e12a8ae51a8a018c89121ab8e4dbf68232 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/UserService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/UserService.kt
@@ -27,14 +27,14 @@ import org.matrix.android.sdk.api.util.Optional
 interface UserService {
 
     /**
-     * Get a user from a userId
+     * Get a user from a userId.
      * @param userId the userId to look for.
      * @return a user with userId or null
      */
     fun getUser(userId: String): User?
 
     /**
-     * Try to resolve user from known users, or using profile api
+     * Try to resolve user from known users, or using profile api.
      */
     suspend fun resolveUser(userId: String): User
 
@@ -48,14 +48,14 @@ interface UserService {
     suspend fun searchUsersDirectory(search: String, limit: Int, excludedUserIds: Set<String>): List<User>
 
     /**
-     * Observe a live user from a userId
+     * Observe a live user from a userId.
      * @param userId the userId to look for.
      * @return a LiveData of user with userId
      */
     fun getUserLive(userId: String): LiveData<Optional<User>>
 
     /**
-     * Observe a live list of users sorted alphabetically
+     * Observe a live list of users sorted alphabetically.
      * @return a Livedata of users
      */
     fun getUsersLive(): LiveData<List<User>>
@@ -69,19 +69,19 @@ interface UserService {
     fun getPagedUsersLive(filter: String? = null, excludedUserIds: Set<String>? = null): LiveData<PagedList<User>>
 
     /**
-     * Get list of ignored users
+     * Get list of ignored users.
      */
     fun getIgnoredUsersLive(): LiveData<List<User>>
 
     /**
-     * Ignore users
+     * Ignore users.
      * Note: once done, for the change to take effect, you have to request an initial sync.
-     * This may be improved in the future
+     * This may be improved in the future.
      */
     suspend fun ignoreUserIds(userIds: List<String>)
 
     /**
-     * Un-ignore some users
+     * Un-ignore some users.
      * Note: once done, for the change to take effect, you have to request an initial sync.
      */
     suspend fun unIgnoreUserIds(userIds: List<String>)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/model/User.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/model/User.kt
index 79c86f3f23165b67c166446b3a2f35c808670d5f..f231e88de0b57c283b9f3e7a74f539f22fac42fe 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/model/User.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/model/User.kt
@@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.util.JsonDict
 data class User(
         val userId: String,
         /**
-         * For usage in UI, consider converting to MatrixItem and call getBestName()
+         * For usage in UI, consider converting to MatrixItem and call getBestName().
          */
         val displayName: String? = null,
         val avatarUrl: String? = null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetPostAPIMediator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetPostAPIMediator.kt
index d8fd00d9e1efd5789e21e2ba8baa8f5fbc2ddc19..edb49f4797f2ac9f6a1cb6862de12052ad03be20 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetPostAPIMediator.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetPostAPIMediator.kt
@@ -47,7 +47,7 @@ interface WidgetPostAPIMediator {
     fun injectAPI()
 
     /**
-     * Send a boolean response
+     * Send a boolean response.
      *
      * @param response  the response
      * @param eventData the modular data
@@ -55,7 +55,7 @@ interface WidgetPostAPIMediator {
     fun sendBoolResponse(response: Boolean, eventData: JsonDict)
 
     /**
-     * Send an integer response
+     * Send an integer response.
      *
      * @param response  the response
      * @param eventData the modular data
@@ -63,7 +63,7 @@ interface WidgetPostAPIMediator {
     fun sendIntegerResponse(response: Int, eventData: JsonDict)
 
     /**
-     * Send an object response
+     * Send an object response.
      *
      * @param klass the class of the response
      * @param response  the response
@@ -72,14 +72,14 @@ interface WidgetPostAPIMediator {
     fun <T> sendObjectResponse(type: Type, response: T?, eventData: JsonDict)
 
     /**
-     * Send success
+     * Send success.
      *
      * @param eventData the modular data
      */
     fun sendSuccess(eventData: JsonDict)
 
     /**
-     * Send an error
+     * Send an error.
      *
      * @param message   the error message
      * @param eventData the modular data
@@ -88,7 +88,7 @@ interface WidgetPostAPIMediator {
 
     interface Handler {
         /**
-         * Triggered when a widget is posting
+         * Triggered when a widget is posting.
          */
         fun handleWidgetRequest(mediator: WidgetPostAPIMediator, eventData: JsonDict): Boolean
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt
index 8f35ff0e4a4532c8efe5da900feb02e66e969664..b06f8f7bc6c682d5d1ec3a297d7ab2c4b0a2ffd5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt
@@ -55,7 +55,7 @@ interface WidgetService {
     ): List<Widget>
 
     /**
-     * Return the computed URL of a widget
+     * Return the computed URL of a widget.
      */
     fun getWidgetComputedUrl(widget: Widget, isLightTheme: Boolean): String?
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/Hash.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/Hash.kt
index 7465eed3aeb1504e9320dda9fcae87a298bfd4d7..22fdd1c610192c5ffbb161b4b57e595bd56f8263 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/Hash.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/Hash.kt
@@ -20,7 +20,7 @@ import java.security.MessageDigest
 import java.util.Locale
 
 /**
- * Compute a Hash of a String, using md5 algorithm
+ * Compute a Hash of a String, using md5 algorithm.
  */
 fun String.md5() = try {
     val digest = MessageDigest.getInstance("md5")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt
index 4f5f4f82d9357c375985888d8a3b08da7c48855d..8a29d003805072d445cee22c9249efbf6b2d97eb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt
@@ -121,7 +121,7 @@ sealed class MatrixItem(
     abstract fun updateAvatar(newAvatar: String?): MatrixItem
 
     /**
-     * Return the prefix as defined in the matrix spec (and not extracted from the id)
+     * Return the prefix as defined in the matrix spec (and not extracted from the id).
      */
     private fun getIdPrefix() = when (this) {
         is UserItem           -> '@'
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixJsonParser.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixJsonParser.kt
index 48a41667b2c669cf5af81a472a373f3d0ab5548c..9927dffa4692dc50f2fd201ead105bfb1a2439a1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixJsonParser.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixJsonParser.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Moshi
 import org.matrix.android.sdk.internal.di.MoshiProvider
 
 /**
- * Entry point to get a Json parser
+ * Entry point to get a Json parser.
  */
 object MatrixJsonParser {
     /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/TextContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/TextContent.kt
index fe12d7b1cfd0cb8712f886ea07b35ede25e891da..2aa548e289a656ae6880ade176747bad125363a7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/TextContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/TextContent.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.api.util
 
 /**
- * Contains a text and eventually a formatted text
+ * Contains a text and eventually a formatted text.
  */
 data class TextContent(
         val text: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt
index ebad859b05178c9b0b8ac79753045606448e9988..46fa63334cb9ed571eb94f33541de0045148cddf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt
@@ -45,26 +45,26 @@ import retrofit2.http.Url
  */
 internal interface AuthAPI {
     /**
-     * Get a Web client config file, using the name including the domain
+     * Get a Web client config file, using the name including the domain.
      */
     @GET("config.{domain}.json")
     suspend fun getWebClientConfigDomain(@Path("domain") domain: String): WebClientConfig
 
     /**
-     * Get a Web client default config file
+     * Get a Web client default config file.
      */
     @GET("config.json")
     suspend fun getWebClientConfig(): WebClientConfig
 
     /**
-     * Get the version information of the homeserver
+     * Get the version information of the homeserver.
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_ + "versions")
     suspend fun versions(): Versions
 
     /**
-     * Register to the homeserver, or get error 401 with a RegistrationFlowResponse object if registration is incomplete
-     * Ref: https://matrix.org/docs/spec/client_server/latest#account-registration-and-management
+     * Register to the homeserver, or get error 401 with a RegistrationFlowResponse object if registration is incomplete.
+     * Ref: https://matrix.org/docs/spec/client_server/latest#account-registration-and-management.
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "register")
     suspend fun register(@Body registrationParams: RegistrationParams): Credentials
@@ -102,14 +102,14 @@ internal interface AuthAPI {
                         @Body params: AddThreePidRegistrationParams): AddThreePidRegistrationResponse
 
     /**
-     * Validate 3pid
+     * Validate 3pid.
      */
     @POST
     suspend fun validate3Pid(@Url url: String,
                              @Body params: ValidationCodeBody): SuccessResult
 
     /**
-     * Get the supported login flow
+     * Get the supported login flow.
      * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-login
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "login")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/Constants.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/Constants.kt
index 3742a429d2de65422fa494a1fda16a127a1628cf..97f8a9d512048c3774eec32c21b86dd37f5e5668 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/Constants.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/Constants.kt
@@ -23,13 +23,13 @@ package org.matrix.android.sdk.internal.auth
 internal const val LOGIN_FALLBACK_PATH = "/_matrix/static/client/login/"
 
 /**
- * Path to use when the client does not supported any or all registration flows
- * Not documented
+ * Path to use when the client does not supported any or all registration flows.
+ * Not documented.
  */
 internal const val REGISTER_FALLBACK_PATH = "/_matrix/static/client/register/"
 
 /**
- * Path to use when the client want to connect using SSO
+ * Path to use when the client want to connect using SSO.
  * Ref: https://matrix.org/docs/spec/client_server/latest#sso-client-login
  */
 internal const val SSO_REDIRECT_PATH = "/_matrix/client/r0/login/sso/redirect"
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt
index 8784d85c1073021869586ea00e1409f5fa38190b..f1cfe3fee5ec6095122af7466c6edccbd9088592 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt
@@ -379,24 +379,33 @@ internal class DefaultAuthenticationService @Inject constructor(
             throw MatrixIdFailure.InvalidMatrixId
         }
 
-        return getWellknownTask.execute(GetWellknownTask.Params(
-                domain = matrixId.getDomain(),
-                homeServerConnectionConfig = homeServerConnectionConfig)
+        return getWellknownTask.execute(
+                GetWellknownTask.Params(
+                        domain = matrixId.getDomain(),
+                        homeServerConnectionConfig = homeServerConnectionConfig.orWellKnownDefaults()
+                )
         )
     }
 
+    private fun HomeServerConnectionConfig?.orWellKnownDefaults() = this ?: HomeServerConnectionConfig.Builder()
+            // server uri is ignored when doing a wellknown lookup as we use the matrix id domain instead
+            .withHomeServerUri("https://dummy.org")
+            .build()
+
     override suspend fun directAuthentication(homeServerConnectionConfig: HomeServerConnectionConfig,
                                               matrixId: String,
                                               password: String,
                                               initialDeviceName: String,
                                               deviceId: String?): Session {
-        return directLoginTask.execute(DirectLoginTask.Params(
-                homeServerConnectionConfig = homeServerConnectionConfig,
-                userId = matrixId,
-                password = password,
-                deviceName = initialDeviceName,
-                deviceId = deviceId
-        ))
+        return directLoginTask.execute(
+                DirectLoginTask.Params(
+                        homeServerConnectionConfig = homeServerConnectionConfig,
+                        userId = matrixId,
+                        password = password,
+                        deviceName = initialDeviceName,
+                        deviceId = deviceId
+                )
+        )
     }
 
     private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/PendingSessionStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/PendingSessionStore.kt
index 06954fa5c299baacd1f43e8eb018515edc0a54ab..7483e2c7d954039a4937c904f3a4313fd21e3633 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/PendingSessionStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/PendingSessionStore.kt
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.auth
 import org.matrix.android.sdk.internal.auth.db.PendingSessionData
 
 /**
- * Store for elements when doing login or registration
+ * Store for elements when doing login or registration.
  */
 internal interface PendingSessionStore {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt
index cc00c963ea1b2550254ccf5346a36f7f1cdbab4f..ba01146a4a7e450e18bf6f62f63193f6fe679110 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/SessionCreator.kt
@@ -39,7 +39,7 @@ internal class DefaultSessionCreator @Inject constructor(
 
     /**
      * Credentials can affect the homeServerConnectionConfig, override homeserver url and/or
-     * identity server url if provided in the credentials
+     * identity server url if provided in the credentials.
      */
     override suspend fun createSession(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session {
         // We can cleanup the pending session params
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt
index c718fae3906e6226a43efeb8e1fcf21c00ff6bb4..df10e110d13828078ca0655393cdd281c668ecc2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/LoginFlowResponse.kt
@@ -23,7 +23,7 @@ import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
 @JsonClass(generateAdapter = true)
 internal data class LoginFlowResponse(
         /**
-         * The homeserver's supported login types
+         * The homeserver's supported login types.
          */
         @Json(name = "flows")
         val flows: List<LoginFlow>?
@@ -39,7 +39,7 @@ internal data class LoginFlow(
 
         /**
          * Augments m.login.sso flow discovery definition to include metadata on the supported IDPs
-         * the client can show a button for each of the supported providers
+         * the client can show a button for each of the supported providers.
          * See MSC #2858
          */
         @Json(name = "identity_providers")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/WebClientConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/WebClientConfig.kt
index 65c3dc64a69cbaeea8cfe2005bdac9fc38ac4beb..a993124a7e33a57895881ae6c59d91a62c74794c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/WebClientConfig.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/WebClientConfig.kt
@@ -22,7 +22,7 @@ import com.squareup.moshi.JsonClass
 @JsonClass(generateAdapter = true)
 internal data class WebClientConfig(
         /**
-         * This is now deprecated, but still used first, rather than value from "default_server_config"
+         * This is now deprecated, but still used first, rather than value from "default_server_config".
          */
         @Json(name = "default_hs_url")
         val defaultHomeServerUrl: String?,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt
index 59b6471a058ed54f7baa7731953ccf462a929932..88c6d04ee67f6f50c222241b6eb209c63be74c3c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmMigration.kt
@@ -27,8 +27,8 @@ import javax.inject.Inject
 
 internal class AuthRealmMigration @Inject constructor() : RealmMigration {
     /**
-     * Forces all AuthRealmMigration instances to be equal
-     * Avoids Realm throwing when multiple instances of the migration are set
+     * Forces all AuthRealmMigration instances to be equal.
+     * Avoids Realm throwing when multiple instances of the migration are set.
      */
     override fun equals(other: Any?) = other is AuthRealmMigration
     override fun hashCode() = 4000
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmModule.kt
index a92384b4edbe9def5c97184b98bfdd8517a15caa..dbf19776021e188b6c99cd82ed5a22d965bde098 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/AuthRealmModule.kt
@@ -19,11 +19,13 @@ package org.matrix.android.sdk.internal.auth.db
 import io.realm.annotations.RealmModule
 
 /**
- * Realm module for authentication classes
+ * Realm module for authentication classes.
  */
-@RealmModule(library = true,
+@RealmModule(
+        library = true,
         classes = [
             SessionParamsEntity::class,
             PendingSessionEntity::class
-        ])
+        ]
+)
 internal class AuthRealmModule
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/PendingSessionData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/PendingSessionData.kt
index 6e13e947f4c65db24247964c7b459f8f5e5351a3..835070d4b78a93109e14a066aba3ce3cd83ec624 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/PendingSessionData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/PendingSessionData.kt
@@ -22,7 +22,7 @@ import org.matrix.android.sdk.internal.auth.registration.ThreePidData
 import java.util.UUID
 
 /**
- * This class holds all pending data when creating a session, either by login or by register
+ * This class holds all pending data when creating a session, either by login or by register.
  */
 internal data class PendingSessionData(
         val homeServerConnectionConfig: HomeServerConnectionConfig,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/PendingSessionMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/PendingSessionMapper.kt
index 8e4043c11b0acfb9b87f668a74211aaeb6ef9b16..1296ea7cc40ffa58fbfb727564b71bf47fc4c6ea 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/PendingSessionMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/PendingSessionMapper.kt
@@ -44,7 +44,8 @@ internal class PendingSessionMapper @Inject constructor(moshi: Moshi) {
                 resetPasswordData = resetPasswordData,
                 currentSession = entity.currentSession,
                 isRegistrationStarted = entity.isRegistrationStarted,
-                currentThreePidData = threePidData)
+                currentThreePidData = threePidData
+        )
     }
 
     fun map(sessionData: PendingSessionData?): PendingSessionEntity? {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsMapper.kt
index 147c0e8be013ca8f7f4623f8805881de558c9167..86929b1afe7f7a9f93ff25b316139eedfd2773e9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/SessionParamsMapper.kt
@@ -54,6 +54,7 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) {
                 sessionParams.userId,
                 credentialsJson,
                 homeServerConnectionConfigJson,
-                sessionParams.isTokenValid)
+                sessionParams.isTokenValid
+        )
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordData.kt
index 06fcacd51495f73e069c6a1ad4708457d9113240..a65ec38d6d851be2bfa9444bc38c351fba1059f3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordData.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistrationResponse
 
 /**
- * Container to store the data when a reset password is in the email validation step
+ * Container to store the data when a reset password is in the email validation step.
  */
 @JsonClass(generateAdapter = true)
 internal data class ResetPasswordData(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt
index f8d17b406adb843b2a3fae051184b82ef25984c5..2f05864d3bfb0252da8de2a399accd47edf75a9d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt
@@ -21,7 +21,7 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
 
 /**
- * Add a three Pid during authentication
+ * Add a three Pid during authentication.
  */
 @JsonClass(generateAdapter = true)
 internal data class AddThreePidRegistrationParams(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AuthParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AuthParams.kt
index cb17207741b9621c769f8a17e57dc52534b69462..6337a6e5c5b09bc7b360054439d4aa752af342bd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AuthParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AuthParams.kt
@@ -21,7 +21,7 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
 
 /**
- * Open class, parent to all possible authentication parameters
+ * Open class, parent to all possible authentication parameters.
  */
 @JsonClass(generateAdapter = true)
 internal data class AuthParams(
@@ -29,19 +29,19 @@ internal data class AuthParams(
         val type: String,
 
         /**
-         * Note: session can be null for reset password request
+         * Note: session can be null for reset password request.
          */
         @Json(name = "session")
         val session: String?,
 
         /**
-         * parameter for "m.login.recaptcha" type
+         * parameter for "m.login.recaptcha" type.
          */
         @Json(name = "response")
         val captchaResponse: String? = null,
 
         /**
-         * parameter for "m.login.email.identity" type
+         * parameter for "m.login.email.identity" type.
          */
         @Json(name = "threepid_creds")
         val threePidCredentials: ThreePidCredentials? = null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt
index 590b333e9008ec64d799db074f19f660bcfd6ec1..8f00f3440c02e2129ad1a0a378b6d5a0f3d7818c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt
@@ -33,7 +33,7 @@ import org.matrix.android.sdk.internal.auth.SessionCreator
 import org.matrix.android.sdk.internal.auth.db.PendingSessionData
 
 /**
- * This class execute the registration request and is responsible to keep the session of interactive authentication
+ * This class execute the registration request and is responsible to keep the session of interactive authentication.
  */
 internal class DefaultRegistrationWizard(
         authAPI: AuthAPI,
@@ -120,21 +120,25 @@ internal class DefaultRegistrationWizard(
                 RegisterAddThreePidTask.Params(
                         threePid,
                         pendingSessionData.clientSecret,
-                        pendingSessionData.sendAttempt))
+                        pendingSessionData.sendAttempt
+                )
+        )
 
         pendingSessionData = pendingSessionData.copy(sendAttempt = pendingSessionData.sendAttempt + 1)
                 .also { pendingSessionStore.savePendingSessionData(it) }
 
         val params = RegistrationParams(
                 auth = if (threePid is RegisterThreePid.Email) {
-                    AuthParams.createForEmailIdentity(safeSession,
+                    AuthParams.createForEmailIdentity(
+                            safeSession,
                             ThreePidCredentials(
                                     clientSecret = pendingSessionData.clientSecret,
                                     sid = response.sid
                             )
                     )
                 } else {
-                    AuthParams.createForMsisdnIdentity(safeSession,
+                    AuthParams.createForMsisdnIdentity(
+                            safeSession,
                             ThreePidCredentials(
                                     clientSecret = pendingSessionData.clientSecret,
                                     sid = response.sid
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ThreePidData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ThreePidData.kt
index 43167062d553f1034b7d433f971ebb1f58221bbf..c8f71af3065192a56a5812e80d15d2ed49213b35 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ThreePidData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ThreePidData.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
 
 /**
- * Container to store the data when a three pid is in validation step
+ * Container to store the data when a three pid is in validation step.
  */
 @JsonClass(generateAdapter = true)
 internal data class ThreePidData(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt
index 7dafacb3c06ad3b8202f0681dc8cf8a323eb3157..9b135c347d427728cd46d0f2fee3983cd93df6d8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt
@@ -26,7 +26,7 @@ import timber.log.Timber
 import kotlin.coroutines.suspendCoroutine
 
 /**
- * Handle a UIA challenge
+ * Handle a UIA challenge.
  *
  * @param failure the failure to handle
  * @param interceptor see doc in [UserInteractiveAuthInterceptor]
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ValidationCodeBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ValidationCodeBody.kt
index ae71ae3a08a23120c956d64338669b15e6c11a64..72b3dc6103978fb7eb6d652a7a2c21af3c2337ba 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ValidationCodeBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ValidationCodeBody.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * This object is used to send a code received by SMS to validate Msisdn ownership
+ * This object is used to send a code received by SMS to validate Msisdn ownership.
  */
 @JsonClass(generateAdapter = true)
 internal data class ValidationCodeBody(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt
index d07d5ecd64b62ba4eef581183557a9d98404f7bf..cee4b12138ed45063314d4c0a8399ba44efd01ee 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Model for https://matrix.org/docs/spec/client_server/latest#get-matrix-client-versions
+ * Model for https://matrix.org/docs/spec/client_server/latest#get-matrix-client-versions.
  *
  * Ex:
  * <pre>
@@ -55,14 +55,14 @@ private const val FEATURE_THREADS_MSC3440 = "org.matrix.msc3440"
 private const val FEATURE_THREADS_MSC3440_STABLE = "org.matrix.msc3440.stable"
 
 /**
- * Return true if the SDK supports this homeserver version
+ * Return true if the SDK supports this homeserver version.
  */
 internal fun Versions.isSupportedBySdk(): Boolean {
     return supportLazyLoadMembers()
 }
 
 /**
- * Return true if the SDK supports this homeserver version for login and registration
+ * Return true if the SDK supports this homeserver version for login and registration.
  */
 internal fun Versions.isLoginAndRegistrationSupportedBySdk(): Boolean {
     return !doesServerRequireIdentityServerParam() &&
@@ -71,15 +71,15 @@ internal fun Versions.isLoginAndRegistrationSupportedBySdk(): Boolean {
 }
 
 /**
- * Indicate if the homeserver support MSC3440 for threads
+ * Indicate if the homeserver support MSC3440 for threads.
  */
 internal fun Versions.doesServerSupportThreads(): Boolean {
-    return getMaxVersion() >= HomeServerVersion.v1_3_0 ||
-            unstableFeatures?.get(FEATURE_THREADS_MSC3440_STABLE) ?: false
+    // TODO Check for v1.3 or whichever spec version formally specifies MSC3440.
+    return unstableFeatures?.get(FEATURE_THREADS_MSC3440_STABLE) ?: false
 }
 
 /**
- * Return true if the server support the lazy loading of room members
+ * Return true if the server support the lazy loading of room members.
  *
  * @return true if the server support the lazy loading of room members
  */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CancelGossipRequestWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CancelGossipRequestWorker.kt
deleted file mode 100644
index aaf23d17b366723fb91587dcd88d8be1dbe6a938..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CancelGossipRequestWorker.kt
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto
-
-import android.content.Context
-import androidx.work.WorkerParameters
-import com.squareup.moshi.JsonClass
-import org.matrix.android.sdk.api.auth.data.Credentials
-import org.matrix.android.sdk.api.failure.shouldBeRetried
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingGossipingRequestState
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.toContent
-import org.matrix.android.sdk.internal.SessionManager
-import org.matrix.android.sdk.internal.crypto.model.rest.ShareRequestCancellation
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
-import org.matrix.android.sdk.internal.crypto.tasks.createUniqueTxnId
-import org.matrix.android.sdk.internal.session.SessionComponent
-import org.matrix.android.sdk.internal.util.time.Clock
-import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
-import org.matrix.android.sdk.internal.worker.SessionWorkerParams
-import javax.inject.Inject
-
-internal class CancelGossipRequestWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
-        SessionSafeCoroutineWorker<CancelGossipRequestWorker.Params>(context, params, sessionManager, Params::class.java) {
-
-    @JsonClass(generateAdapter = true)
-    internal data class Params(
-            override val sessionId: String,
-            val requestId: String,
-            val recipients: Map<String, List<String>>,
-            // The txnId for the sendToDevice request. Nullable for compatibility reasons, but MUST always be provided
-            // to use the same value if this worker is retried.
-            val txnId: String? = null,
-            override val lastFailureMessage: String? = null
-    ) : SessionWorkerParams {
-        companion object {
-            fun fromRequest(sessionId: String, request: OutgoingGossipingRequest): Params {
-                return Params(
-                        sessionId = sessionId,
-                        requestId = request.requestId,
-                        recipients = request.recipients,
-                        txnId = createUniqueTxnId(),
-                        lastFailureMessage = null
-                )
-            }
-        }
-    }
-
-    @Inject lateinit var sendToDeviceTask: SendToDeviceTask
-    @Inject lateinit var cryptoStore: IMXCryptoStore
-    @Inject lateinit var credentials: Credentials
-    @Inject lateinit var clock: Clock
-
-    override fun injectWith(injector: SessionComponent) {
-        injector.inject(this)
-    }
-
-    override suspend fun doSafeWork(params: Params): Result {
-        // params.txnId should be provided in all cases now. But Params can be deserialized by
-        // the WorkManager from data serialized in a previous version of the application, so without the txnId field.
-        // So if not present, we create a txnId
-        val txnId = params.txnId ?: createUniqueTxnId()
-        val contentMap = MXUsersDevicesMap<Any>()
-        val toDeviceContent = ShareRequestCancellation(
-                requestingDeviceId = credentials.deviceId,
-                requestId = params.requestId
-        )
-        cryptoStore.saveGossipingEvent(Event(
-                type = EventType.ROOM_KEY_REQUEST,
-                content = toDeviceContent.toContent(),
-                senderId = credentials.userId
-        ).also {
-            it.ageLocalTs = clock.epochMillis()
-        })
-
-        params.recipients.forEach { userToDeviceMap ->
-            userToDeviceMap.value.forEach { deviceId ->
-                contentMap.setObject(userToDeviceMap.key, deviceId, toDeviceContent)
-            }
-        }
-
-        try {
-            cryptoStore.updateOutgoingGossipingRequestState(params.requestId, OutgoingGossipingRequestState.CANCELLING)
-            sendToDeviceTask.execute(
-                    SendToDeviceTask.Params(
-                            eventType = EventType.ROOM_KEY_REQUEST,
-                            contentMap = contentMap,
-                            transactionId = txnId
-                    )
-            )
-            cryptoStore.updateOutgoingGossipingRequestState(params.requestId, OutgoingGossipingRequestState.CANCELLED)
-            return Result.success()
-        } catch (throwable: Throwable) {
-            return if (throwable.shouldBeRetried()) {
-                Result.retry()
-            } else {
-                cryptoStore.updateOutgoingGossipingRequestState(params.requestId, OutgoingGossipingRequestState.FAILED_TO_CANCEL)
-                buildErrorResult(params, throwable.localizedMessage ?: "error")
-            }
-        }
-    }
-
-    override fun buildErrorParams(params: Params, message: String): Params {
-        return params.copy(lastFailureMessage = params.lastFailureMessage ?: message)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt
index 73dfc468d97a2ba35189dfdb0ac7eaae954c1d96..b3e9eab9880b1f0fa8ec3d372940273abc42530b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt
@@ -28,7 +28,7 @@ import javax.inject.Inject
 
 /**
  * The crypto module needs some information regarding rooms that are stored
- * in the session DB, this class encapsulate this functionality
+ * in the session DB, this class encapsulate this functionality.
  */
 internal class CryptoSessionInfoProvider @Inject constructor(
         @SessionDatabase private val monarchy: Monarchy
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
index 54c9990bf623ffaf4b3ea88cb3488f264c67c7c9..11fa93dbe05753ac457afa7298de581415329123 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
@@ -42,12 +42,14 @@ import org.matrix.android.sdk.api.logger.LoggerTag
 import org.matrix.android.sdk.api.session.crypto.CryptoService
 import org.matrix.android.sdk.api.session.crypto.MXCryptoError
 import org.matrix.android.sdk.api.session.crypto.NewSessionListener
+import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest
 import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
 import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
 import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
 import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
 import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
 import org.matrix.android.sdk.api.session.crypto.keyshare.GossipingRequestListener
+import org.matrix.android.sdk.api.session.crypto.model.AuditTrail
 import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
 import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
 import org.matrix.android.sdk.api.session.crypto.model.DevicesListResponse
@@ -57,15 +59,13 @@ import org.matrix.android.sdk.api.session.crypto.model.MXDeviceInfo
 import org.matrix.android.sdk.api.session.crypto.model.MXEncryptEventContentResult
 import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult
 import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingRoomKeyRequest
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
+import org.matrix.android.sdk.api.session.crypto.model.RoomKeyShareRequest
+import org.matrix.android.sdk.api.session.crypto.model.TrailType
 import org.matrix.android.sdk.api.session.events.model.Content
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
 import org.matrix.android.sdk.api.session.events.model.content.RoomKeyContent
 import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
-import org.matrix.android.sdk.api.session.events.model.content.SecretSendEventContent
 import org.matrix.android.sdk.api.session.events.model.toModel
 import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
@@ -76,7 +76,6 @@ import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
 import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
 import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting
 import org.matrix.android.sdk.internal.crypto.algorithms.IMXGroupEncryption
-import org.matrix.android.sdk.internal.crypto.algorithms.IMXWithHeldExtension
 import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory
 import org.matrix.android.sdk.internal.crypto.algorithms.olm.MXOlmEncryptionFactory
 import org.matrix.android.sdk.internal.crypto.crosssigning.DefaultCrossSigningService
@@ -91,6 +90,7 @@ import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask
 import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask
 import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask
 import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationService
+import org.matrix.android.sdk.internal.crypto.verification.VerificationMessageProcessor
 import org.matrix.android.sdk.internal.di.DeviceId
 import org.matrix.android.sdk.internal.di.MoshiProvider
 import org.matrix.android.sdk.internal.di.UserId
@@ -156,9 +156,10 @@ internal class DefaultCryptoService @Inject constructor(
 
         private val crossSigningService: DefaultCrossSigningService,
         //
-        private val incomingGossipingRequestManager: IncomingGossipingRequestManager,
+        private val incomingKeyRequestManager: IncomingKeyRequestManager,
+        private val secretShareManager: SecretShareManager,
         //
-        private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
+        private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
         // Actions
         private val setDeviceVerificationAction: SetDeviceVerificationAction,
         private val megolmSessionDataImporter: MegolmSessionDataImporter,
@@ -178,6 +179,7 @@ internal class DefaultCryptoService @Inject constructor(
         private val taskExecutor: TaskExecutor,
         private val cryptoCoroutineScope: CoroutineScope,
         private val eventDecryptor: EventDecryptor,
+        private val verificationMessageProcessor: VerificationMessageProcessor,
         private val liveEventManager: Lazy<StreamEventsManager>
 ) : CryptoService {
 
@@ -192,7 +194,7 @@ internal class DefaultCryptoService @Inject constructor(
         }
     }
 
-    fun onLiveEvent(roomId: String, event: Event) {
+    fun onLiveEvent(roomId: String, event: Event, isInitialSync: Boolean) {
         // handle state events
         if (event.isStateEvent()) {
             when (event.type) {
@@ -201,9 +203,18 @@ internal class DefaultCryptoService @Inject constructor(
                 EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
             }
         }
+
+        // handle verification
+        if (!isInitialSync) {
+            if (event.type != null && verificationMessageProcessor.shouldProcess(event.type)) {
+                cryptoCoroutineScope.launch(coroutineDispatchers.dmVerif) {
+                    verificationMessageProcessor.process(event)
+                }
+            }
+        }
     }
 
-    val gossipingBuffer = mutableListOf<Event>()
+//    val gossipingBuffer = mutableListOf<Event>()
 
     override fun setDeviceName(deviceId: String, deviceName: String, callback: MatrixCallback<Unit>) {
         setDeviceNameTask
@@ -282,7 +293,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     /**
-     * Provides the tracking status
+     * Provides the tracking status.
      *
      * @param userId the user id
      * @return the tracking status
@@ -292,7 +303,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     /**
-     * Tell if the MXCrypto is started
+     * Tell if the MXCrypto is started.
      *
      * @return true if the crypto is started
      */
@@ -379,35 +390,17 @@ internal class DefaultCryptoService @Inject constructor(
         // Open the store
         cryptoStore.open()
 
-        runCatching {
-//            if (isInitialSync) {
-//                // refresh the devices list for each known room members
-//                deviceListManager.invalidateAllDeviceLists()
-//                deviceListManager.refreshOutdatedDeviceLists()
-//            } else {
-
-            // Why would we do that? it will be called at end of syn
-            incomingGossipingRequestManager.processReceivedGossipingRequests()
-//            }
-        }.fold(
-                {
-                    isStarting.set(false)
-                    isStarted.set(true)
-                },
-                {
-                    isStarting.set(false)
-                    isStarted.set(false)
-                    Timber.tag(loggerTag.value).e(it, "Start failed")
-                }
-        )
+        isStarting.set(false)
+        isStarted.set(true)
     }
 
     /**
-     * Close the crypto
+     * Close the crypto.
      */
     fun close() = runBlocking(coroutineDispatchers.crypto) {
         cryptoCoroutineScope.coroutineContext.cancelChildren(CancellationException("Closing crypto module"))
-        incomingGossipingRequestManager.close()
+        incomingKeyRequestManager.close()
+        outgoingKeyRequestManager.close()
         olmDevice.release()
         cryptoStore.close()
     }
@@ -428,7 +421,7 @@ internal class DefaultCryptoService @Inject constructor(
     override fun crossSigningService() = crossSigningService
 
     /**
-     * A sync response has been received
+     * A sync response has been received.
      *
      * @param syncResponse the syncResponse
      */
@@ -472,21 +465,34 @@ internal class DefaultCryptoService @Inject constructor(
                     }
 
                     oneTimeKeysUploader.maybeUploadOneTimeKeys()
-                    incomingGossipingRequestManager.processReceivedGossipingRequests()
                 }
-            }
 
-            tryOrNull {
-                gossipingBuffer.toList().let {
-                    cryptoStore.saveGossipingEvents(it)
+                // Process pending key requests
+                try {
+                    if (toDevices.isEmpty()) {
+                        // this is not blocking
+                        outgoingKeyRequestManager.requireProcessAllPendingKeyRequests()
+                    } else {
+                        Timber.tag(loggerTag.value)
+                                .w("Don't process key requests yet as there might be more to_device to catchup")
+                    }
+                } catch (failure: Throwable) {
+                    // just for safety but should not throw
+                    Timber.tag(loggerTag.value).w("failed to process pending request")
+                }
+
+                try {
+                    incomingKeyRequestManager.processIncomingRequests()
+                } catch (failure: Throwable) {
+                    // just for safety but should not throw
+                    Timber.tag(loggerTag.value).w("failed to process incoming room key requests")
                 }
-                gossipingBuffer.clear()
             }
         }
     }
 
     /**
-     * Find a device by curve25519 identity key
+     * Find a device by curve25519 identity key.
      *
      * @param senderKey the curve25519 key to match.
      * @param algorithm the encryption algorithm.
@@ -500,7 +506,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     /**
-     * Provides the device information for a user id and a device Id
+     * Provides the device information for a user id and a device Id.
      *
      * @param userId   the user id
      * @param deviceId the device id
@@ -530,7 +536,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     /**
-     * Set the devices as known
+     * Set the devices as known.
      *
      * @param devices  the devices. Note that the verified member of the devices in this list will not be updated by this method.
      * @param callback the asynchronous callback
@@ -594,7 +600,7 @@ internal class DefaultCryptoService @Inject constructor(
         // (for now at least. Maybe we should alert the user somehow?)
         val existingAlgorithm = cryptoStore.getRoomAlgorithm(roomId)
 
-        if (existingAlgorithm == algorithm && roomEncryptorsStore.get(roomId) != null) {
+        if (existingAlgorithm == algorithm) {
             // ignore
             Timber.tag(loggerTag.value).e("setEncryptionInRoom() : Ignoring m.room.encryption for same alg ($algorithm) in  $roomId")
             return false
@@ -641,7 +647,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     /**
-     * Tells if a room is encrypted with MXCRYPTO_ALGORITHM_MEGOLM
+     * Tells if a room is encrypted with MXCRYPTO_ALGORITHM_MEGOLM.
      *
      * @param roomId the room id
      * @return true if the room is encrypted with algorithm MXCRYPTO_ALGORITHM_MEGOLM
@@ -712,8 +718,10 @@ internal class DefaultCryptoService @Inject constructor(
                 }.foldToCallback(callback)
             } else {
                 val algorithm = getEncryptionAlgorithm(roomId)
-                val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
-                        algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON)
+                val reason = String.format(
+                        MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
+                        algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON
+                )
                 Timber.tag(loggerTag.value).e("encryptEventContent() : failed $reason")
                 callback.onFailure(Failure.CryptoError(MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_ENCRYPT, reason)))
             }
@@ -732,7 +740,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     /**
-     * Decrypt an event
+     * Decrypt an event.
      *
      * @param event    the raw event.
      * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
@@ -744,7 +752,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     /**
-     * Decrypt an event asynchronously
+     * Decrypt an event asynchronously.
      *
      * @param event    the raw event.
      * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
@@ -755,7 +763,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     /**
-     * Decrypt an event
+     * Decrypt an event.
      *
      * @param event    the raw event.
      * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
@@ -776,7 +784,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     /**
-     * Handle the 'toDevice' event
+     * Handle the 'toDevice' event.
      *
      * @param event the event
      */
@@ -785,19 +793,25 @@ internal class DefaultCryptoService @Inject constructor(
         cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
             when (event.getClearType()) {
                 EventType.ROOM_KEY, EventType.FORWARDED_ROOM_KEY -> {
-                    gossipingBuffer.add(event)
                     // Keys are imported directly, not waiting for end of sync
                     onRoomKeyEvent(event)
                 }
-                EventType.REQUEST_SECRET,
+                EventType.REQUEST_SECRET                         -> {
+                    secretShareManager.handleSecretRequest(event)
+                }
                 EventType.ROOM_KEY_REQUEST                       -> {
-                    // save audit trail
-                    gossipingBuffer.add(event)
-                    // Requests are stacked, and will be handled one by one at the end of the sync (onSyncComplete)
-                    incomingGossipingRequestManager.onGossipingRequestEvent(event)
+                    event.getClearContent().toModel<RoomKeyShareRequest>()?.let { req ->
+                        // We'll always get these because we send room key requests to
+                        // '*' (ie. 'all devices') which includes the sending device,
+                        // so ignore requests from ourself because apart from it being
+                        // very silly, it won't work because an Olm session cannot send
+                        // messages to itself.
+                        if (req.requestingDeviceId != deviceId) { // ignore self requests
+                            event.senderId?.let { incomingKeyRequestManager.addNewIncomingRequest(it, req) }
+                        }
+                    }
                 }
                 EventType.SEND_SECRET                            -> {
-                    gossipingBuffer.add(event)
                     onSecretSendReceived(event)
                 }
                 EventType.ROOM_KEY_WITHHELD                      -> {
@@ -835,50 +849,38 @@ internal class DefaultCryptoService @Inject constructor(
         val withHeldContent = event.getClearContent().toModel<RoomKeyWithHeldContent>() ?: return Unit.also {
             Timber.tag(loggerTag.value).i("Malformed onKeyWithHeldReceived() : missing fields")
         }
-        Timber.tag(loggerTag.value).i("onKeyWithHeldReceived() received from:${event.senderId}, content <$withHeldContent>")
-        val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(withHeldContent.roomId, withHeldContent.algorithm)
-        if (alg is IMXWithHeldExtension) {
-            alg.onRoomKeyWithHeldEvent(withHeldContent)
-        } else {
-            Timber.tag(loggerTag.value).e("onKeyWithHeldReceived() from:${event.senderId}: Unable to handle WithHeldContent for ${withHeldContent.algorithm}")
-            return
+        val senderId = event.senderId ?: return Unit.also {
+            Timber.tag(loggerTag.value).i("Malformed onKeyWithHeldReceived() : missing fields")
         }
+        withHeldContent.sessionId ?: return
+        withHeldContent.algorithm ?: return
+        withHeldContent.roomId ?: return
+        withHeldContent.senderKey ?: return
+        outgoingKeyRequestManager.onRoomKeyWithHeld(
+                sessionId = withHeldContent.sessionId,
+                algorithm = withHeldContent.algorithm,
+                roomId = withHeldContent.roomId,
+                senderKey = withHeldContent.senderKey,
+                fromDevice = withHeldContent.fromDevice,
+                event = Event(
+                        type = EventType.ROOM_KEY_WITHHELD,
+                        senderId = senderId,
+                        content = event.getClearContent()
+                )
+        )
     }
 
-    private fun onSecretSendReceived(event: Event) {
-        Timber.tag(loggerTag.value).i("GOSSIP onSecretSend() from ${event.senderId} : onSecretSendReceived ${event.content?.get("sender_key")}")
-        if (!event.isEncrypted()) {
-            // secret send messages must be encrypted
-            Timber.tag(loggerTag.value).e("GOSSIP onSecretSend() :Received unencrypted secret send event")
-            return
-        }
-
-        // Was that sent by us?
-        if (event.senderId != userId) {
-            Timber.tag(loggerTag.value).e("GOSSIP onSecretSend() : Ignore secret from other user ${event.senderId}")
-            return
-        }
-
-        val secretContent = event.getClearContent().toModel<SecretSendEventContent>() ?: return
-
-        val existingRequest = cryptoStore
-                .getOutgoingSecretKeyRequests().firstOrNull { it.requestId == secretContent.requestId }
-
-        if (existingRequest == null) {
-            Timber.tag(loggerTag.value).i("GOSSIP onSecretSend() : Ignore secret that was not requested: ${secretContent.requestId}")
-            return
-        }
-
-        if (!handleSDKLevelGossip(existingRequest.secretName, secretContent.secretValue)) {
-            // TODO Ask to application layer?
-            Timber.tag(loggerTag.value).v("onSecretSend() : secret not handled by SDK")
+    private suspend fun onSecretSendReceived(event: Event) {
+        secretShareManager.onSecretSendReceived(event) { secretName, secretValue ->
+            handleSDKLevelGossip(secretName, secretValue)
         }
     }
 
     /**
-     * Returns true if handled by SDK, otherwise should be sent to application layer
+     * Returns true if handled by SDK, otherwise should be sent to application layer.
      */
-    private fun handleSDKLevelGossip(secretName: String?, secretValue: String): Boolean {
+    private fun handleSDKLevelGossip(secretName: String?,
+                                     secretValue: String): Boolean {
         return when (secretName) {
             MASTER_KEY_SSSS_NAME       -> {
                 crossSigningService.onSecretMSKGossip(secretValue)
@@ -982,7 +984,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     /**
-     * Export the crypto keys
+     * Export the crypto keys.
      *
      * @param password the password
      * @return the exported keys
@@ -992,7 +994,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     /**
-     * Export the crypto keys
+     * Export the crypto keys.
      *
      * @param password         the password
      * @param anIterationCount the encryption iteration count (0 means no encryption)
@@ -1011,7 +1013,7 @@ internal class DefaultCryptoService @Inject constructor(
     }
 
     /**
-     * Import the room keys
+     * Import the room keys.
      *
      * @param roomKeysAsArray  the room keys as array.
      * @param password         the password
@@ -1093,6 +1095,12 @@ internal class DefaultCryptoService @Inject constructor(
         cryptoStore.setGlobalBlacklistUnverifiedDevices(block)
     }
 
+    override fun enableKeyGossiping(enable: Boolean) {
+        cryptoStore.enableKeyGossiping(enable)
+    }
+
+    override fun isKeyGossipingEnabled() = cryptoStore.isKeyGossipingEnabled()
+
     /**
      * Tells whether the client should ever send encrypted messages to unverified devices.
      * The default value is false.
@@ -1156,52 +1164,17 @@ internal class DefaultCryptoService @Inject constructor(
         setRoomBlacklistUnverifiedDevices(roomId, false)
     }
 
-// TODO Check if this method is still necessary
-    /**
-     * Cancel any earlier room key request
-     *
-     * @param requestBody requestBody
-     */
-    override fun cancelRoomKeyRequest(requestBody: RoomKeyRequestBody) {
-        outgoingGossipingRequestManager.cancelRoomKeyRequest(requestBody)
-    }
-
     /**
      * Re request the encryption keys required to decrypt an event.
      *
      * @param event the event to decrypt again.
      */
     override fun reRequestRoomKeyForEvent(event: Event) {
-        val wireContent = event.content.toModel<EncryptedEventContent>() ?: return Unit.also {
-            Timber.tag(loggerTag.value).e("reRequestRoomKeyForEvent Failed to re-request key, null content")
-        }
-
-        val requestBody = RoomKeyRequestBody(
-                algorithm = wireContent.algorithm,
-                roomId = event.roomId,
-                senderKey = wireContent.senderKey,
-                sessionId = wireContent.sessionId
-        )
-
-        outgoingGossipingRequestManager.resendRoomKeyRequest(requestBody)
+        outgoingKeyRequestManager.requestKeyForEvent(event, true)
     }
 
     override fun requestRoomKeyForEvent(event: Event) {
-        val wireContent = event.content.toModel<EncryptedEventContent>() ?: return Unit.also {
-            Timber.tag(loggerTag.value).e("requestRoomKeyForEvent Failed to request key, null content eventId: ${event.eventId}")
-        }
-
-        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
-//            if (!isStarted()) {
-//                Timber.v("## CRYPTO | requestRoomKeyForEvent() : wait after e2e init")
-//                internalStart(false)
-//            }
-            roomDecryptorProvider
-                    .getOrCreateRoomDecryptor(event.roomId, wireContent.algorithm)
-                    ?.requestKeysForEvent(event, false) ?: run {
-                Timber.tag(loggerTag.value).v("requestRoomKeyForEvent() : No room decryptor for roomId:${event.roomId} algorithm:${wireContent.algorithm}")
-            }
-        }
+        outgoingKeyRequestManager.requestKeyForEvent(event, false)
     }
 
     /**
@@ -1210,7 +1183,8 @@ internal class DefaultCryptoService @Inject constructor(
      * @param listener listener
      */
     override fun addRoomKeysRequestListener(listener: GossipingRequestListener) {
-        incomingGossipingRequestManager.addRoomKeysRequestListener(listener)
+        incomingKeyRequestManager.addRoomKeysRequestListener(listener)
+        secretShareManager.addListener(listener)
     }
 
     /**
@@ -1219,44 +1193,12 @@ internal class DefaultCryptoService @Inject constructor(
      * @param listener listener
      */
     override fun removeRoomKeysRequestListener(listener: GossipingRequestListener) {
-        incomingGossipingRequestManager.removeRoomKeysRequestListener(listener)
-    }
-
-//    private fun markOlmSessionForUnwedging(senderId: String, deviceInfo: CryptoDeviceInfo) {
-//        val deviceKey = deviceInfo.identityKey()
-//
-//        val lastForcedDate = lastNewSessionForcedDates.getObject(senderId, deviceKey) ?: 0
-//        val now = clock.epochMillis()
-//        if (now - lastForcedDate < CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
-//            Timber.d("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
-//            return
-//        }
-//
-//        Timber.d("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
-//        lastNewSessionForcedDates.setObject(senderId, deviceKey, now)
-//
-//        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
-//            ensureOlmSessionsForDevicesAction.handle(mapOf(senderId to listOf(deviceInfo)), force = true)
-//
-//            // Now send a blank message on that session so the other side knows about it.
-//            // (The keyshare request is sent in the clear so that won't do)
-//            // We send this first such that, as long as the toDevice messages arrive in the
-//            // same order we sent them, the other end will get this first, set up the new session,
-//            // then get the keyshare request and send the key over this new session (because it
-//            // is the session it has most recently received a message on).
-//            val payloadJson = mapOf<String, Any>("type" to EventType.DUMMY)
-//
-//            val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
-//            val sendToDeviceMap = MXUsersDevicesMap<Any>()
-//            sendToDeviceMap.setObject(senderId, deviceInfo.deviceId, encodedPayload)
-//            Timber.v("## CRYPTO | markOlmSessionForUnwedging() : sending to $senderId:${deviceInfo.deviceId}")
-//            val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
-//            sendToDeviceTask.execute(sendToDeviceParams)
-//        }
-//    }
+        incomingKeyRequestManager.removeRoomKeysRequestListener(listener)
+        secretShareManager.removeListener(listener)
+    }
 
     /**
-     * Provides the list of unknown devices
+     * Provides the list of unknown devices.
      *
      * @param devicesInRoom the devices map
      * @return the unknown devices map
@@ -1300,27 +1242,41 @@ internal class DefaultCryptoService @Inject constructor(
         return "DefaultCryptoService of $userId ($deviceId)"
     }
 
-    override fun getOutgoingRoomKeyRequests(): List<OutgoingRoomKeyRequest> {
+    override fun getOutgoingRoomKeyRequests(): List<OutgoingKeyRequest> {
         return cryptoStore.getOutgoingRoomKeyRequests()
     }
 
-    override fun getOutgoingRoomKeyRequestsPaged(): LiveData<PagedList<OutgoingRoomKeyRequest>> {
+    override fun getOutgoingRoomKeyRequestsPaged(): LiveData<PagedList<OutgoingKeyRequest>> {
         return cryptoStore.getOutgoingRoomKeyRequestsPaged()
     }
 
+    override fun getIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest> {
+        return cryptoStore.getGossipingEvents()
+                .mapNotNull {
+                    IncomingRoomKeyRequest.fromEvent(it)
+                }
+    }
+
     override fun getIncomingRoomKeyRequestsPaged(): LiveData<PagedList<IncomingRoomKeyRequest>> {
-        return cryptoStore.getIncomingRoomKeyRequestsPaged()
+        return cryptoStore.getGossipingEventsTrail(TrailType.IncomingKeyRequest) {
+            IncomingRoomKeyRequest.fromEvent(it)
+                    ?: IncomingRoomKeyRequest(localCreationTimestamp = 0L)
+        }
     }
 
-    override fun getIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest> {
-        return cryptoStore.getIncomingRoomKeyRequests()
+    /**
+     * If you registered a `GossipingRequestListener`, you will be notified of key request
+     * that was not accepted by the SDK. You can call back this manually to accept anyhow.
+     */
+    override suspend fun manuallyAcceptRoomKeyRequest(request: IncomingRoomKeyRequest) {
+        incomingKeyRequestManager.manuallyAcceptRoomKeyRequest(request)
     }
 
-    override fun getGossipingEventsTrail(): LiveData<PagedList<Event>> {
+    override fun getGossipingEventsTrail(): LiveData<PagedList<AuditTrail>> {
         return cryptoStore.getGossipingEventsTrail()
     }
 
-    override fun getGossipingEvents(): List<Event> {
+    override fun getGossipingEvents(): List<AuditTrail> {
         return cryptoStore.getGossipingEvents()
     }
 
@@ -1344,8 +1300,8 @@ internal class DefaultCryptoService @Inject constructor(
                 loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId))
             } catch (failure: Throwable) {
                 Timber.tag(loggerTag.value).e("prepareToEncrypt() : Failed to load room members")
-                callback.onFailure(failure)
-                return@launch
+                // we probably shouldn't block sending on that (but questionable)
+                // but some members won't be able to decrypt
             }
 
             val userIds = getRoomUserIds(roomId)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
index 535999373b8434d21cd0a6c12cfe471b50a0c8ff..cd4e2a6d527663b4dd2a572ab20ce1cea4b969d1 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
@@ -102,7 +102,7 @@ internal class DeviceListManager @Inject constructor(
     }
 
     /**
-     * Tells if the key downloads should be tried
+     * Tells if the key downloads should be tried.
      *
      * @param userId the userId
      * @return true if the keys download can be retrieved
@@ -124,7 +124,7 @@ internal class DeviceListManager @Inject constructor(
     }
 
     /**
-     * Clear the unavailable server lists
+     * Clear the unavailable server lists.
      */
     private fun clearUnavailableServersList() {
         synchronized(notReadyToRetryHS) {
@@ -167,7 +167,7 @@ internal class DeviceListManager @Inject constructor(
     }
 
     /**
-     * Update the devices list statuses
+     * Update the devices list statuses.
      *
      * @param changed the user ids list which have new devices
      * @param left    the user ids list which left a room
@@ -203,15 +203,14 @@ internal class DeviceListManager @Inject constructor(
     }
 
     /**
-     * This will flag each user whose devices we are tracking as in need of an
-     * + update
+     * This will flag each user whose devices we are tracking as in need of an update.
      */
     fun invalidateAllDeviceLists() {
         handleDeviceListsChanges(cryptoStore.getDeviceTrackingStatuses().keys, emptyList())
     }
 
     /**
-     * The keys download failed
+     * The keys download failed.
      *
      * @param userIds the user ids list
      */
@@ -315,10 +314,19 @@ internal class DeviceListManager @Inject constructor(
         } else {
             Timber.v("## CRYPTO | downloadKeys() : starts")
             val t0 = clock.epochMillis()
-            val result = doKeyDownloadForUsers(downloadUsers)
-            Timber.v("## CRYPTO | downloadKeys() : doKeyDownloadForUsers succeeds after ${clock.epochMillis() - t0} ms")
-            result.also {
-                it.addEntriesFromMap(stored)
+            try {
+                val result = doKeyDownloadForUsers(downloadUsers)
+                Timber.v("## CRYPTO | downloadKeys() : doKeyDownloadForUsers succeeds after ${clock.epochMillis() - t0} ms")
+                result.also {
+                    it.addEntriesFromMap(stored)
+                }
+            } catch (failure: Throwable) {
+                Timber.w(failure, "## CRYPTO | downloadKeys() : doKeyDownloadForUsers failed after ${clock.epochMillis() - t0} ms")
+                if (forceDownload) {
+                    throw failure
+                } else {
+                    stored
+                }
             }
         }
     }
@@ -543,7 +551,7 @@ internal class DeviceListManager @Inject constructor(
     companion object {
 
         /**
-         * State transition diagram for DeviceList.deviceTrackingStatus
+         * State transition diagram for DeviceList.deviceTrackingStatus.
          * <pre>
          *
          *                                   |
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt
index a09418964538a74890aa9cd1fa66e9c9809ea4e4..d6f881211c8c3f8848f6d1c840ff9503d90038da 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt
@@ -70,7 +70,7 @@ internal class EventDecryptor @Inject constructor(
     private val wedgedDevices = mutableListOf<WedgedDeviceInfo>()
 
     /**
-     * Decrypt an event
+     * Decrypt an event.
      *
      * @param event    the raw event.
      * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
@@ -82,7 +82,7 @@ internal class EventDecryptor @Inject constructor(
     }
 
     /**
-     * Decrypt an event asynchronously
+     * Decrypt an event asynchronously.
      *
      * @param event    the raw event.
      * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
@@ -98,7 +98,7 @@ internal class EventDecryptor @Inject constructor(
     }
 
     /**
-     * Decrypt an event
+     * Decrypt an event.
      *
      * @param event    the raw event.
      * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/GossipingWorkManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/GossipingWorkManager.kt
deleted file mode 100644
index a2c85e5ceb1e825e5f3d61481d14f3263a160691..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/GossipingWorkManager.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto
-
-import androidx.work.BackoffPolicy
-import androidx.work.Data
-import androidx.work.ExistingWorkPolicy
-import androidx.work.ListenableWorker
-import androidx.work.OneTimeWorkRequest
-import org.matrix.android.sdk.api.util.Cancelable
-import org.matrix.android.sdk.internal.di.WorkManagerProvider
-import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.util.CancelableWork
-import org.matrix.android.sdk.internal.worker.startChain
-import java.util.UUID
-import java.util.concurrent.TimeUnit
-import javax.inject.Inject
-
-@SessionScope
-internal class GossipingWorkManager @Inject constructor(
-        private val workManagerProvider: WorkManagerProvider
-) {
-
-    inline fun <reified W : ListenableWorker> createWork(data: Data, startChain: Boolean): OneTimeWorkRequest {
-        return workManagerProvider.matrixOneTimeWorkRequestBuilder<W>()
-                .setConstraints(WorkManagerProvider.workConstraints)
-                .startChain(startChain)
-                .setInputData(data)
-                .setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
-                .build()
-    }
-
-    // Prevent sending queue to stay broken after app restart
-    // The unique queue id will stay the same as long as this object is instantiated
-    private val queueSuffixApp = UUID.randomUUID()
-
-    fun postWork(workRequest: OneTimeWorkRequest, policy: ExistingWorkPolicy = ExistingWorkPolicy.APPEND): Cancelable {
-        workManagerProvider.workManager
-                .beginUniqueWork(this::class.java.name + "_$queueSuffixApp", policy, workRequest)
-                .enqueue()
-
-        return CancelableWork(workManagerProvider.workManager, workRequest.id)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt
deleted file mode 100644
index 1612caba9fa55cf3532be20e93e4e4f4bb7f7883..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.api.auth.data.Credentials
-import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
-import org.matrix.android.sdk.api.crypto.MXCryptoConfig
-import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
-import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
-import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
-import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
-import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromRecoveryKey
-import org.matrix.android.sdk.api.session.crypto.keyshare.GossipingRequestListener
-import org.matrix.android.sdk.api.session.crypto.model.GossipingRequestState
-import org.matrix.android.sdk.api.session.crypto.model.GossipingToDeviceObject
-import org.matrix.android.sdk.api.session.crypto.model.IncomingRequestCancellation
-import org.matrix.android.sdk.api.session.crypto.model.IncomingRoomKeyRequest
-import org.matrix.android.sdk.api.session.crypto.model.IncomingSecretShareRequest
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.toModel
-import org.matrix.android.sdk.api.util.toBase64NoPadding
-import org.matrix.android.sdk.internal.crypto.algorithms.IMXGroupEncryption
-import org.matrix.android.sdk.internal.crypto.model.rest.GossipingDefaultContent
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.createUniqueTxnId
-import org.matrix.android.sdk.internal.di.SessionId
-import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.util.time.Clock
-import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
-import timber.log.Timber
-import java.util.concurrent.Executors
-import javax.inject.Inject
-
-@SessionScope
-internal class IncomingGossipingRequestManager @Inject constructor(
-        @SessionId private val sessionId: String,
-        private val credentials: Credentials,
-        private val cryptoStore: IMXCryptoStore,
-        private val cryptoConfig: MXCryptoConfig,
-        private val gossipingWorkManager: GossipingWorkManager,
-        private val roomEncryptorsStore: RoomEncryptorsStore,
-        private val roomDecryptorProvider: RoomDecryptorProvider,
-        private val coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val cryptoCoroutineScope: CoroutineScope,
-        private val clock: Clock,
-) {
-
-    private val executor = Executors.newSingleThreadExecutor()
-
-    // list of IncomingRoomKeyRequests/IncomingRoomKeyRequestCancellations
-    // we received in the current sync.
-    private val receivedGossipingRequests = ArrayList<IncomingShareRequestCommon>()
-    private val receivedRequestCancellations = ArrayList<IncomingRequestCancellation>()
-
-    // the listeners
-    private val gossipingRequestListeners: MutableSet<GossipingRequestListener> = HashSet()
-
-    init {
-        receivedGossipingRequests.addAll(cryptoStore.getPendingIncomingGossipingRequests())
-    }
-
-    fun close() {
-        executor.shutdownNow()
-    }
-
-    // Recently verified devices (map of deviceId and timestamp)
-    private val recentlyVerifiedDevices = HashMap<String, Long>()
-
-    /**
-     * Called when a session has been verified.
-     * This information can be used by the manager to decide whether or not to fullfil gossiping requests
-     */
-    fun onVerificationCompleteForDevice(deviceId: String) {
-        // For now we just keep an in memory cache
-        synchronized(recentlyVerifiedDevices) {
-            recentlyVerifiedDevices[deviceId] = clock.epochMillis()
-        }
-    }
-
-    private fun hasBeenVerifiedLessThanFiveMinutesFromNow(deviceId: String): Boolean {
-        val verifTimestamp: Long?
-        synchronized(recentlyVerifiedDevices) {
-            verifTimestamp = recentlyVerifiedDevices[deviceId]
-        }
-        if (verifTimestamp == null) return false
-
-        val age = clock.epochMillis() - verifTimestamp
-
-        return age < FIVE_MINUTES_IN_MILLIS
-    }
-
-    /**
-     * Called when we get an m.room_key_request event
-     * It must be called on CryptoThread
-     *
-     * @param event the announcement event.
-     */
-    fun onGossipingRequestEvent(event: Event) {
-        val roomKeyShare = event.getClearContent().toModel<GossipingDefaultContent>()
-        Timber.i("## CRYPTO | GOSSIP onGossipingRequestEvent received type ${event.type} from user:${event.senderId}, content:$roomKeyShare")
-        // val ageLocalTs = event.unsignedData?.age?.let { clock.epochMillis() - it }
-        when (roomKeyShare?.action) {
-            GossipingToDeviceObject.ACTION_SHARE_REQUEST      -> {
-                if (event.getClearType() == EventType.REQUEST_SECRET) {
-                    IncomingSecretShareRequest.fromEvent(event, clock.epochMillis())?.let {
-                        if (event.senderId == credentials.userId && it.deviceId == credentials.deviceId) {
-                            // ignore, it was sent by me as *
-                            Timber.v("## GOSSIP onGossipingRequestEvent type ${event.type} ignore remote echo")
-                        } else {
-//                            // save in DB
-//                            cryptoStore.storeIncomingGossipingRequest(it, ageLocalTs)
-                            receivedGossipingRequests.add(it)
-                        }
-                    }
-                } else if (event.getClearType() == EventType.ROOM_KEY_REQUEST) {
-                    IncomingRoomKeyRequest.fromEvent(event, clock.epochMillis())?.let {
-                        if (event.senderId == credentials.userId && it.deviceId == credentials.deviceId) {
-                            // ignore, it was sent by me as *
-                            Timber.v("## GOSSIP onGossipingRequestEvent type ${event.type} ignore remote echo")
-                        } else {
-//                            cryptoStore.storeIncomingGossipingRequest(it, ageLocalTs)
-                            receivedGossipingRequests.add(it)
-                        }
-                    }
-                }
-            }
-            GossipingToDeviceObject.ACTION_SHARE_CANCELLATION -> {
-                IncomingRequestCancellation.fromEvent(event, clock.epochMillis())?.let {
-                    receivedRequestCancellations.add(it)
-                }
-            }
-            else                                              -> {
-                Timber.e("## GOSSIP onGossipingRequestEvent() : unsupported action ${roomKeyShare?.action}")
-            }
-        }
-    }
-
-    /**
-     * Process any m.room_key_request or m.secret.request events which were queued up during the
-     * current sync.
-     * It must be called on CryptoThread
-     */
-    fun processReceivedGossipingRequests() {
-        val roomKeyRequestsToProcess = receivedGossipingRequests.toList()
-        receivedGossipingRequests.clear()
-
-        Timber.v("## CRYPTO | GOSSIP processReceivedGossipingRequests() : ${roomKeyRequestsToProcess.size} request to process")
-
-        var receivedRequestCancellations: List<IncomingRequestCancellation>? = null
-
-        synchronized(this.receivedRequestCancellations) {
-            if (this.receivedRequestCancellations.isNotEmpty()) {
-                receivedRequestCancellations = this.receivedRequestCancellations.toList()
-                this.receivedRequestCancellations.clear()
-            }
-        }
-
-        executor.execute {
-            cryptoStore.storeIncomingGossipingRequests(roomKeyRequestsToProcess)
-            for (request in roomKeyRequestsToProcess) {
-                if (request is IncomingRoomKeyRequest) {
-                    processIncomingRoomKeyRequest(request)
-                } else if (request is IncomingSecretShareRequest) {
-                    processIncomingSecretShareRequest(request)
-                }
-            }
-
-            receivedRequestCancellations?.forEach { request ->
-                Timber.v("## CRYPTO | GOSSIP processReceivedGossipingRequests() : m.room_key_request cancellation $request")
-                // we should probably only notify the app of cancellations we told it
-                // about, but we don't currently have a record of that, so we just pass
-                // everything through.
-                if (request.userId == credentials.userId && request.deviceId == credentials.deviceId) {
-                    // ignore remote echo
-                    return@forEach
-                }
-                val matchingIncoming = cryptoStore.getIncomingRoomKeyRequest(request.userId ?: "", request.deviceId ?: "", request.requestId ?: "")
-                if (matchingIncoming == null) {
-                    // ignore that?
-                    return@forEach
-                } else {
-                    // If it was accepted from this device, keep the information, do not mark as cancelled
-                    if (matchingIncoming.state != GossipingRequestState.ACCEPTED) {
-                        onRoomKeyRequestCancellation(request)
-                        cryptoStore.updateGossipingRequestState(request, GossipingRequestState.CANCELLED_BY_REQUESTER)
-                    }
-                }
-            }
-        }
-    }
-
-    private fun processIncomingRoomKeyRequest(request: IncomingRoomKeyRequest) {
-        val userId = request.userId ?: return
-        val deviceId = request.deviceId ?: return
-        val body = request.requestBody ?: return
-        val roomId = body.roomId ?: return
-        val alg = body.algorithm ?: return
-
-        Timber.v("## CRYPTO | GOSSIP processIncomingRoomKeyRequest from $userId:$deviceId for $roomId / ${body.sessionId} id ${request.requestId}")
-        if (credentials.userId != userId) {
-            handleKeyRequestFromOtherUser(body, request, alg, roomId, userId, deviceId)
-            return
-        }
-        // TODO: should we queue up requests we don't yet have keys for, in case they turn up later?
-        // if we don't have a decryptor for this room/alg, we don't have
-        // the keys for the requested events, and can drop the requests.
-        val decryptor = roomDecryptorProvider.getRoomDecryptor(roomId, alg)
-        if (null == decryptor) {
-            Timber.w("## CRYPTO | GOSSIP processReceivedGossipingRequests() : room key request for unknown $alg in room $roomId")
-            cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-            return
-        }
-        if (!decryptor.hasKeysForKeyRequest(request)) {
-            Timber.w("## CRYPTO | GOSSIP processReceivedGossipingRequests() : room key request for unknown session ${body.sessionId!!}")
-            cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-            return
-        }
-
-        if (credentials.deviceId == deviceId && credentials.userId == userId) {
-            Timber.v("## CRYPTO | GOSSIP processReceivedGossipingRequests() : oneself device - ignored")
-            cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-            return
-        }
-        request.share = Runnable {
-            decryptor.shareKeysWithDevice(request)
-            cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTED)
-        }
-        request.ignore = Runnable {
-            cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-        }
-        // if the device is verified already, share the keys
-        val device = cryptoStore.getUserDevice(userId, deviceId)
-        if (device != null) {
-            if (device.isVerified) {
-                Timber.v("## CRYPTO | GOSSIP processReceivedGossipingRequests() : device is already verified: sharing keys")
-                request.share?.run()
-                return
-            }
-
-            if (device.isBlocked) {
-                Timber.v("## CRYPTO | GOSSIP processReceivedGossipingRequests() : device is blocked -> ignored")
-                cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-                return
-            }
-        }
-
-        // As per config we automatically discard untrusted devices request
-        if (cryptoConfig.discardRoomKeyRequestsFromUntrustedDevices) {
-            Timber.v("## CRYPTO | processReceivedGossipingRequests() : discardRoomKeyRequestsFromUntrustedDevices")
-            // At this point the device is unknown, we don't want to bother user with that
-            cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-            return
-        }
-
-        // Pass to application layer to decide what to do
-        onRoomKeyRequest(request)
-    }
-
-    private fun handleKeyRequestFromOtherUser(body: RoomKeyRequestBody,
-                                              request: IncomingRoomKeyRequest,
-                                              alg: String,
-                                              roomId: String,
-                                              userId: String,
-                                              deviceId: String) {
-        Timber.w("## CRYPTO | GOSSIP processReceivedGossipingRequests() : room key request from other user")
-        val senderKey = body.senderKey ?: return Unit
-                .also { Timber.w("missing senderKey") }
-                .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) }
-        val sessionId = body.sessionId ?: return Unit
-                .also { Timber.w("missing sessionId") }
-                .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) }
-
-        if (alg != MXCRYPTO_ALGORITHM_MEGOLM) {
-            return Unit
-                    .also { Timber.w("Only megolm is accepted here") }
-                    .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) }
-        }
-
-        val roomEncryptor = roomEncryptorsStore.get(roomId) ?: return Unit
-                .also { Timber.w("no room Encryptor") }
-                .also { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) }
-
-        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
-            if (roomEncryptor is IMXGroupEncryption) {
-                val isSuccess = roomEncryptor.reshareKey(sessionId, userId, deviceId, senderKey)
-
-                if (isSuccess) {
-                    cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTED)
-                } else {
-                    cryptoStore.updateGossipingRequestState(request, GossipingRequestState.UNABLE_TO_PROCESS)
-                }
-            } else {
-                Timber.e("## CRYPTO | handleKeyRequestFromOtherUser() from:$userId: Unable to handle IMXGroupEncryption.reshareKey for $alg")
-            }
-        }
-        cryptoStore.updateGossipingRequestState(request, GossipingRequestState.RE_REQUESTED)
-    }
-
-    private fun processIncomingSecretShareRequest(request: IncomingSecretShareRequest) {
-        val secretName = request.secretName ?: return Unit.also {
-            cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-            Timber.v("## CRYPTO | GOSSIP processIncomingSecretShareRequest() : Missing secret name")
-        }
-
-        val userId = request.userId
-        if (userId == null || credentials.userId != userId) {
-            Timber.e("## CRYPTO | GOSSIP processIncomingSecretShareRequest() : Ignoring secret share request from other users")
-            cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-            return
-        }
-
-        val deviceId = request.deviceId
-                ?: return Unit.also {
-                    Timber.e("## CRYPTO | GOSSIP processIncomingSecretShareRequest() : Malformed request, no ")
-                    cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-                }
-
-        val device = cryptoStore.getUserDevice(userId, deviceId)
-                ?: return Unit.also {
-                    Timber.e("## CRYPTO | GOSSIP processIncomingSecretShareRequest() : Received secret share request from unknown device ${request.deviceId}")
-                    cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-                }
-
-        if (!device.isVerified || device.isBlocked) {
-            Timber.v("## CRYPTO | GOSSIP processIncomingSecretShareRequest() : Ignoring secret share request from untrusted/blocked session $device")
-            cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-            return
-        }
-
-        val isDeviceLocallyVerified = cryptoStore.getUserDevice(userId, deviceId)?.trustLevel?.isLocallyVerified()
-
-        when (secretName) {
-            MASTER_KEY_SSSS_NAME       -> cryptoStore.getCrossSigningPrivateKeys()?.master
-            SELF_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.selfSigned
-            USER_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.user
-            KEYBACKUP_SECRET_SSSS_NAME -> cryptoStore.getKeyBackupRecoveryKeyInfo()?.recoveryKey
-                    ?.let {
-                        extractCurveKeyFromRecoveryKey(it)?.toBase64NoPadding()
-                    }
-            else                       -> null
-        }?.let { secretValue ->
-            Timber.i("## CRYPTO | GOSSIP processIncomingSecretShareRequest() : Sharing secret $secretName with $device locally trusted")
-            if (isDeviceLocallyVerified == true && hasBeenVerifiedLessThanFiveMinutesFromNow(deviceId)) {
-                val params = SendGossipWorker.Params(
-                        sessionId = sessionId,
-                        secretValue = secretValue,
-                        requestUserId = request.userId,
-                        requestDeviceId = request.deviceId,
-                        requestId = request.requestId,
-                        txnId = createUniqueTxnId()
-                )
-
-                cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTING)
-                val workRequest = gossipingWorkManager.createWork<SendGossipWorker>(WorkerParamsFactory.toData(params), true)
-                gossipingWorkManager.postWork(workRequest)
-            } else {
-                Timber.v("## CRYPTO | GOSSIP processIncomingSecretShareRequest() : Can't share secret $secretName with $device, verification too old")
-                cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-            }
-            return
-        }
-
-        Timber.v("## CRYPTO | GOSSIP processIncomingSecretShareRequest() : $secretName unknown at SDK level, asking to app layer")
-
-        request.ignore = Runnable {
-            cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED)
-        }
-
-        request.share = { secretValue ->
-            val params = SendGossipWorker.Params(
-                    sessionId = userId,
-                    secretValue = secretValue,
-                    requestUserId = request.userId,
-                    requestDeviceId = request.deviceId,
-                    requestId = request.requestId,
-                    txnId = createUniqueTxnId()
-            )
-
-            cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTING)
-            val workRequest = gossipingWorkManager.createWork<SendGossipWorker>(WorkerParamsFactory.toData(params), true)
-            gossipingWorkManager.postWork(workRequest)
-            cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTED)
-        }
-
-        onShareRequest(request)
-    }
-
-    /**
-     * Dispatch onRoomKeyRequest
-     *
-     * @param request the request
-     */
-    private fun onRoomKeyRequest(request: IncomingRoomKeyRequest) {
-        synchronized(gossipingRequestListeners) {
-            for (listener in gossipingRequestListeners) {
-                try {
-                    listener.onRoomKeyRequest(request)
-                } catch (e: Exception) {
-                    Timber.e(e, "## CRYPTO | onRoomKeyRequest() failed")
-                }
-            }
-        }
-    }
-
-    /**
-     * Ask for a value to the listeners, and take the first one
-     */
-    private fun onShareRequest(request: IncomingSecretShareRequest) {
-        synchronized(gossipingRequestListeners) {
-            for (listener in gossipingRequestListeners) {
-                try {
-                    if (listener.onSecretShareRequest(request)) {
-                        return
-                    }
-                } catch (e: Exception) {
-                    Timber.e(e, "## CRYPTO | GOSSIP onRoomKeyRequest() failed")
-                }
-            }
-        }
-        // Not handled, ignore
-        request.ignore?.run()
-    }
-
-    /**
-     * A room key request cancellation has been received.
-     *
-     * @param request the cancellation request
-     */
-    private fun onRoomKeyRequestCancellation(request: IncomingRequestCancellation) {
-        synchronized(gossipingRequestListeners) {
-            for (listener in gossipingRequestListeners) {
-                try {
-                    listener.onRoomKeyRequestCancellation(request)
-                } catch (e: Exception) {
-                    Timber.e(e, "## CRYPTO | GOSSIP onRoomKeyRequestCancellation() failed")
-                }
-            }
-        }
-    }
-
-    fun addRoomKeysRequestListener(listener: GossipingRequestListener) {
-        synchronized(gossipingRequestListeners) {
-            gossipingRequestListeners.add(listener)
-        }
-    }
-
-    fun removeRoomKeysRequestListener(listener: GossipingRequestListener) {
-        synchronized(gossipingRequestListeners) {
-            gossipingRequestListeners.remove(listener)
-        }
-    }
-
-    companion object {
-        private const val FIVE_MINUTES_IN_MILLIS = 5 * 60 * 1000
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt
new file mode 100644
index 0000000000000000000000000000000000000000..13f2fb861abca650f8d9616b2b3592429293bbfa
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.internal.crypto
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.asCoroutineDispatcher
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.withContext
+import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
+import org.matrix.android.sdk.api.auth.data.Credentials
+import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
+import org.matrix.android.sdk.api.crypto.MXCryptoConfig
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.logger.LoggerTag
+import org.matrix.android.sdk.api.session.crypto.keyshare.GossipingRequestListener
+import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
+import org.matrix.android.sdk.api.session.crypto.model.IncomingRoomKeyRequest
+import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
+import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
+import org.matrix.android.sdk.api.session.crypto.model.RoomKeyShareRequest
+import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
+import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
+import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
+import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
+import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
+import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
+import org.matrix.android.sdk.internal.session.SessionScope
+import org.matrix.android.sdk.internal.task.SemaphoreCoroutineSequencer
+import org.matrix.android.sdk.internal.util.time.Clock
+import timber.log.Timber
+import java.util.concurrent.Executors
+import javax.inject.Inject
+import kotlin.system.measureTimeMillis
+
+private val loggerTag = LoggerTag("IncomingKeyRequestManager", LoggerTag.CRYPTO)
+
+@SessionScope
+internal class IncomingKeyRequestManager @Inject constructor(
+        private val credentials: Credentials,
+        private val cryptoStore: IMXCryptoStore,
+        private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
+        private val olmDevice: MXOlmDevice,
+        private val cryptoConfig: MXCryptoConfig,
+        private val messageEncrypter: MessageEncrypter,
+        private val coroutineDispatchers: MatrixCoroutineDispatchers,
+        private val sendToDeviceTask: SendToDeviceTask,
+        private val clock: Clock,
+) {
+
+    private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
+    private val outgoingRequestScope = CoroutineScope(SupervisorJob() + dispatcher)
+    val sequencer = SemaphoreCoroutineSequencer()
+
+    private val incomingRequestBuffer = mutableListOf<ValidMegolmRequestBody>()
+
+    // the listeners
+    private val gossipingRequestListeners: MutableSet<GossipingRequestListener> = HashSet()
+
+    enum class MegolmRequestAction {
+        Request, Cancel
+    }
+
+    data class ValidMegolmRequestBody(
+            val requestId: String,
+            val requestingUserId: String,
+            val requestingDeviceId: String,
+            val roomId: String,
+            val senderKey: String,
+            val sessionId: String,
+            val action: MegolmRequestAction
+    ) {
+        fun shortDbgString() = "Request from $requestingUserId|$requestingDeviceId for session $sessionId in room $roomId"
+    }
+
+    private fun RoomKeyShareRequest.toValidMegolmRequest(senderId: String): ValidMegolmRequestBody? {
+        val deviceId = requestingDeviceId ?: return null
+        val body = body ?: return null
+        val roomId = body.roomId ?: return null
+        val sessionId = body.sessionId ?: return null
+        val senderKey = body.senderKey ?: return null
+        val requestId = this.requestId ?: return null
+        if (body.algorithm != MXCRYPTO_ALGORITHM_MEGOLM) return null
+        val action = when (this.action) {
+            "request" -> MegolmRequestAction.Request
+            "request_cancellation" -> MegolmRequestAction.Cancel
+            else -> null
+        } ?: return null
+        return ValidMegolmRequestBody(
+                requestId = requestId,
+                requestingUserId = senderId,
+                requestingDeviceId = deviceId,
+                roomId = roomId,
+                senderKey = senderKey,
+                sessionId = sessionId,
+                action = action
+        )
+    }
+
+    fun addNewIncomingRequest(senderId: String, request: RoomKeyShareRequest) {
+        if (!cryptoStore.isKeyGossipingEnabled()) {
+            Timber.tag(loggerTag.value)
+                    .i("Ignore incoming key request as per crypto config in room ${request.body?.roomId}")
+            return
+        }
+        outgoingRequestScope.launch {
+            // It is important to handle requests in order
+            sequencer.post {
+                val validMegolmRequest = request.toValidMegolmRequest(senderId) ?: return@post Unit.also {
+                    Timber.tag(loggerTag.value).w("Received key request for unknown algorithm ${request.body?.algorithm}")
+                }
+
+                // is there already one like that?
+                val existing = incomingRequestBuffer.firstOrNull { it == validMegolmRequest }
+                if (existing == null) {
+                    when (validMegolmRequest.action) {
+                        MegolmRequestAction.Request -> {
+                            // just add to the buffer
+                            incomingRequestBuffer.add(validMegolmRequest)
+                        }
+                        MegolmRequestAction.Cancel  -> {
+                            // ignore, we can't cancel as it's not known (probably already processed)
+                            // still notify app layer if it was passed up previously
+                            IncomingRoomKeyRequest.fromRestRequest(senderId, request, clock)?.let { iReq ->
+                                outgoingRequestScope.launch(coroutineDispatchers.computation) {
+                                    val listenersCopy = synchronized(gossipingRequestListeners) {
+                                        gossipingRequestListeners.toList()
+                                    }
+                                    listenersCopy.onEach {
+                                        tryOrNull {
+                                            withContext(coroutineDispatchers.main) {
+                                                it.onRequestCancelled(iReq)
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    when (validMegolmRequest.action) {
+                        MegolmRequestAction.Request -> {
+                            // it's already in buffer, nop keep existing
+                        }
+                        MegolmRequestAction.Cancel  -> {
+                            // discard the request in buffer
+                            incomingRequestBuffer.remove(existing)
+                            outgoingRequestScope.launch(coroutineDispatchers.computation) {
+                                val listenersCopy = synchronized(gossipingRequestListeners) {
+                                    gossipingRequestListeners.toList()
+                                }
+                                listenersCopy.onEach {
+                                    IncomingRoomKeyRequest.fromRestRequest(senderId, request, clock)?.let { iReq ->
+                                        withContext(coroutineDispatchers.main) {
+                                            tryOrNull { it.onRequestCancelled(iReq) }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    fun processIncomingRequests() {
+        outgoingRequestScope.launch {
+            sequencer.post {
+                measureTimeMillis {
+                    Timber.tag(loggerTag.value).v("processIncomingKeyRequests : ${incomingRequestBuffer.size} request to process")
+                    incomingRequestBuffer.forEach {
+                        // should not happen, we only store requests
+                        if (it.action != MegolmRequestAction.Request) return@forEach
+                        try {
+                            handleIncomingRequest(it)
+                        } catch (failure: Throwable) {
+                            // ignore and continue, should not happen
+                            Timber.tag(loggerTag.value).w(failure, "processIncomingKeyRequests : failed to process request $it")
+                        }
+                    }
+                    incomingRequestBuffer.clear()
+                }.let { duration ->
+                    Timber.tag(loggerTag.value).v("Finish processing incoming key request in $duration ms")
+                }
+            }
+        }
+    }
+
+    private suspend fun handleIncomingRequest(request: ValidMegolmRequestBody) {
+        // We don't want to download keys, if we don't know the device yet we won't share any how?
+        val requestingDevice =
+                cryptoStore.getUserDevice(request.requestingUserId, request.requestingDeviceId)
+                        ?: return Unit.also {
+                            Timber.tag(loggerTag.value).d("Ignoring key request: ${request.shortDbgString()}")
+                        }
+
+        cryptoStore.saveIncomingKeyRequestAuditTrail(
+                request.requestId,
+                request.roomId,
+                request.sessionId,
+                request.senderKey,
+                MXCRYPTO_ALGORITHM_MEGOLM,
+                request.requestingUserId,
+                request.requestingDeviceId
+        )
+
+        val roomAlgorithm = // withContext(coroutineDispatchers.crypto) {
+                cryptoStore.getRoomAlgorithm(request.roomId)
+//        }
+        if (roomAlgorithm != MXCRYPTO_ALGORITHM_MEGOLM) {
+            // strange we received a request for a room that is not encrypted
+            // maybe a broken state?
+            Timber.tag(loggerTag.value).w("Received a key request in a room with unsupported alg:$roomAlgorithm , req:${request.shortDbgString()}")
+            return
+        }
+
+        // Is it for one of our sessions?
+        if (request.requestingUserId == credentials.userId) {
+            Timber.tag(loggerTag.value).v("handling request from own user: megolm session ${request.sessionId}")
+
+            if (request.requestingDeviceId == credentials.deviceId) {
+                // ignore it's a remote echo
+                return
+            }
+            // If it's verified we share from the early index we know
+            // if not we check if it was originaly shared or not
+            if (requestingDevice.isVerified) {
+                // we share from the earliest known chain index
+                shareMegolmKey(request, requestingDevice, null)
+            } else {
+                shareIfItWasPreviouslyShared(request, requestingDevice)
+            }
+        } else {
+            if (cryptoConfig.limitRoomKeyRequestsToMyDevices) {
+                Timber.tag(loggerTag.value).v("Ignore request from other user as per crypto config: ${request.shortDbgString()}")
+                return
+            }
+            Timber.tag(loggerTag.value).v("handling request from other user: megolm session ${request.sessionId}")
+            if (requestingDevice.isBlocked) {
+                // it's blocked, so send a withheld code
+                sendWithheldForRequest(request, WithHeldCode.BLACKLISTED)
+            } else {
+                shareIfItWasPreviouslyShared(request, requestingDevice)
+            }
+        }
+    }
+
+    private suspend fun shareIfItWasPreviouslyShared(request: ValidMegolmRequestBody, requestingDevice: CryptoDeviceInfo) {
+        // we don't reshare unless it was previously shared with
+        val wasSessionSharedWithUser = withContext(coroutineDispatchers.crypto) {
+            cryptoStore.getSharedSessionInfo(request.roomId, request.sessionId, requestingDevice)
+        }
+        if (wasSessionSharedWithUser.found && wasSessionSharedWithUser.chainIndex != null) {
+            // we share from the index it was previously shared with
+            shareMegolmKey(request, requestingDevice, wasSessionSharedWithUser.chainIndex.toLong())
+        } else {
+            val isOwnDevice = requestingDevice.userId == credentials.userId
+            sendWithheldForRequest(request, if (isOwnDevice) WithHeldCode.UNVERIFIED else WithHeldCode.UNAUTHORISED)
+            // if it's our device we could delegate to the app layer to decide
+            if (isOwnDevice) {
+                outgoingRequestScope.launch(coroutineDispatchers.computation) {
+                    val listenersCopy = synchronized(gossipingRequestListeners) {
+                        gossipingRequestListeners.toList()
+                    }
+                    val iReq = IncomingRoomKeyRequest(
+                            userId = requestingDevice.userId,
+                            deviceId = requestingDevice.deviceId,
+                            requestId = request.requestId,
+                            requestBody = RoomKeyRequestBody(
+                                    algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
+                                    senderKey = request.senderKey,
+                                    sessionId = request.sessionId,
+                                    roomId = request.roomId
+                            ),
+                            localCreationTimestamp = clock.epochMillis()
+                    )
+                    listenersCopy.onEach {
+                        withContext(coroutineDispatchers.main) {
+                            tryOrNull { it.onRoomKeyRequest(iReq) }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private suspend fun sendWithheldForRequest(request: ValidMegolmRequestBody, code: WithHeldCode) {
+        Timber.tag(loggerTag.value)
+                .w("Send withheld $code for req: ${request.shortDbgString()}")
+        val withHeldContent = RoomKeyWithHeldContent(
+                roomId = request.roomId,
+                senderKey = request.senderKey,
+                algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
+                sessionId = request.sessionId,
+                codeString = code.value,
+                fromDevice = credentials.deviceId
+        )
+
+        val params = SendToDeviceTask.Params(
+                EventType.ROOM_KEY_WITHHELD,
+                MXUsersDevicesMap<Any>().apply {
+                    setObject(request.requestingUserId, request.requestingDeviceId, withHeldContent)
+                }
+        )
+        try {
+            withContext(coroutineDispatchers.io) {
+                sendToDeviceTask.execute(params)
+                Timber.tag(loggerTag.value)
+                        .d("Send withheld $code req: ${request.shortDbgString()}")
+            }
+
+            cryptoStore.saveWithheldAuditTrail(
+                    roomId = request.roomId,
+                    sessionId = request.sessionId,
+                    senderKey = request.senderKey,
+                    algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
+                    code = code,
+                    userId = request.requestingUserId,
+                    deviceId = request.requestingDeviceId
+            )
+        } catch (failure: Throwable) {
+            // Ignore it's not that important?
+            // do we want to fallback to a worker?
+            Timber.tag(loggerTag.value)
+                    .w("Failed to send withheld $code req: ${request.shortDbgString()} reason:${failure.localizedMessage}")
+        }
+    }
+
+    suspend fun manuallyAcceptRoomKeyRequest(request: IncomingRoomKeyRequest) {
+        request.requestId ?: return
+        request.deviceId ?: return
+        request.userId ?: return
+        request.requestBody?.roomId ?: return
+        request.requestBody.senderKey ?: return
+        request.requestBody.sessionId ?: return
+        val validReq = ValidMegolmRequestBody(
+                requestId = request.requestId,
+                requestingDeviceId = request.deviceId,
+                requestingUserId = request.userId,
+                roomId = request.requestBody.roomId,
+                senderKey = request.requestBody.senderKey,
+                sessionId = request.requestBody.sessionId,
+                action = MegolmRequestAction.Request
+        )
+        val requestingDevice =
+                cryptoStore.getUserDevice(request.userId, request.deviceId)
+                        ?: return Unit.also {
+                            Timber.tag(loggerTag.value).d("Ignoring key request: ${validReq.shortDbgString()}")
+                        }
+
+        shareMegolmKey(validReq, requestingDevice, null)
+    }
+
+    private suspend fun shareMegolmKey(validRequest: ValidMegolmRequestBody,
+                                       requestingDevice: CryptoDeviceInfo,
+                                       chainIndex: Long?): Boolean {
+        Timber.tag(loggerTag.value)
+                .d("try to re-share Megolm Key at index $chainIndex for ${validRequest.shortDbgString()}")
+
+        val devicesByUser = mapOf(validRequest.requestingUserId to listOf(requestingDevice))
+        val usersDeviceMap = try {
+            ensureOlmSessionsForDevicesAction.handle(devicesByUser)
+        } catch (failure: Throwable) {
+            Timber.tag(loggerTag.value)
+                    .w("Failed to establish olm session")
+            sendWithheldForRequest(validRequest, WithHeldCode.NO_OLM)
+            return false
+        }
+
+        val olmSessionResult = usersDeviceMap.getObject(requestingDevice.userId, requestingDevice.deviceId)
+        if (olmSessionResult?.sessionId == null) {
+            Timber.tag(loggerTag.value)
+                    .w("reshareKey: no session with this device, probably because there were no one-time keys")
+            sendWithheldForRequest(validRequest, WithHeldCode.NO_OLM)
+            return false
+        }
+        val sessionHolder = try {
+            olmDevice.getInboundGroupSession(validRequest.sessionId, validRequest.senderKey, validRequest.roomId)
+        } catch (failure: Throwable) {
+            Timber.tag(loggerTag.value)
+                    .e(failure, "shareKeysWithDevice: failed to get session ${validRequest.requestingUserId}")
+            // It's unavailable
+            sendWithheldForRequest(validRequest, WithHeldCode.UNAVAILABLE)
+            return false
+        }
+
+        val export = sessionHolder.mutex.withLock {
+            sessionHolder.wrapper.exportKeys(chainIndex)
+        } ?: return false.also {
+            Timber.tag(loggerTag.value)
+                    .e("shareKeysWithDevice: failed to export group session ${validRequest.sessionId}")
+        }
+
+        val payloadJson = mapOf(
+                "type" to EventType.FORWARDED_ROOM_KEY,
+                "content" to export
+        )
+
+        val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(requestingDevice))
+        val sendToDeviceMap = MXUsersDevicesMap<Any>()
+        sendToDeviceMap.setObject(requestingDevice.userId, requestingDevice.deviceId, encodedPayload)
+        Timber.tag(loggerTag.value).d("reshareKey() : try sending session ${validRequest.sessionId} to ${requestingDevice.shortDebugString()}")
+        val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
+        return try {
+            sendToDeviceTask.execute(sendToDeviceParams)
+            Timber.tag(loggerTag.value)
+                    .i("successfully re-shared session ${validRequest.sessionId} to ${requestingDevice.shortDebugString()}")
+            cryptoStore.saveForwardKeyAuditTrail(
+                    validRequest.roomId,
+                    validRequest.sessionId,
+                    validRequest.senderKey,
+                    MXCRYPTO_ALGORITHM_MEGOLM,
+                    requestingDevice.userId,
+                    requestingDevice.deviceId,
+                    chainIndex
+            )
+            true
+        } catch (failure: Throwable) {
+            Timber.tag(loggerTag.value)
+                    .e(failure, "fail to re-share session ${validRequest.sessionId} to ${requestingDevice.shortDebugString()}")
+            false
+        }
+    }
+
+    fun addRoomKeysRequestListener(listener: GossipingRequestListener) {
+        synchronized(gossipingRequestListeners) {
+            gossipingRequestListeners.add(listener)
+        }
+    }
+
+    fun removeRoomKeysRequestListener(listener: GossipingRequestListener) {
+        synchronized(gossipingRequestListeners) {
+            gossipingRequestListeners.remove(listener)
+        }
+    }
+
+    fun close() {
+        try {
+            outgoingRequestScope.cancel("User Terminate")
+            incomingRequestBuffer.clear()
+        } catch (failure: Throwable) {
+            Timber.tag(loggerTag.value).w("Failed to shutDown request manager")
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingShareRequestCommon.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingShareRequestCommon.kt
deleted file mode 100644
index 97c369db3ec7cb48b1d9c0cffeefbeff995f5136..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingShareRequestCommon.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto
-
-internal interface IncomingShareRequestCommon {
-    /**
-     * The user id
-     */
-    val userId: String?
-
-    /**
-     * The device id
-     */
-    val deviceId: String?
-
-    /**
-     * The request id
-     */
-    val requestId: String?
-
-    val localCreationTimestamp: Long?
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXMegolmExportEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXMegolmExportEncryption.kt
index 89e38cb7cfc418d88f7d1b27bc9d827bd497f2c9..e4a0f0376e04079a4cbc64c95972981b3f11c87a 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXMegolmExportEncryption.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXMegolmExportEncryption.kt
@@ -32,7 +32,7 @@ import kotlin.math.min
 import kotlin.system.measureTimeMillis
 
 /**
- * Utility class to import/export the crypto data
+ * Utility class to import/export the crypto data.
  */
 internal object MXMegolmExportEncryption {
     private const val HEADER_LINE = "-----BEGIN MEGOLM SESSION DATA-----"
@@ -66,7 +66,7 @@ internal object MXMegolmExportEncryption {
     }
 
     /**
-     * Decrypt a megolm key file
+     * Decrypt a megolm key file.
      *
      * @param data     the data to decrypt
      * @param password the password.
@@ -209,8 +209,8 @@ internal object MXMegolmExportEncryption {
     }
 
     /**
-     * Unbase64 an ascii-armoured megolm key file
-     * Strips the header and trailer lines, and unbase64s the content
+     * Unbase64 an ascii-armoured megolm key file.
+     * Strips the header and trailer lines, and unbase64s the content.
      *
      * @param data the input data
      * @return unbase64ed content
@@ -302,7 +302,7 @@ internal object MXMegolmExportEncryption {
     }
 
     /**
-     * Derive the AES and HMAC-SHA-256 keys for the file
+     * Derive the AES and HMAC-SHA-256 keys for the file.
      *
      * @param salt       salt for pbkdf
      * @param iterations number of pbkdf iterations
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt
index 7eec83abddf0b501daab4a3cf860567b2d7bae1d..5620cbf7693dab07ec101ae72b0869b2bf4ff306 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt
@@ -43,7 +43,6 @@ import org.matrix.olm.OlmOutboundGroupSession
 import org.matrix.olm.OlmSession
 import org.matrix.olm.OlmUtility
 import timber.log.Timber
-import java.net.URLEncoder
 import javax.inject.Inject
 
 private val loggerTag = LoggerTag("MXOlmDevice", LoggerTag.CRYPTO)
@@ -149,9 +148,9 @@ internal class MXOlmDevice @Inject constructor(
     }
 
     /**
-     * Returns an unpublished fallback key
+     * Returns an unpublished fallback key.
      * A call to markKeysAsPublished will mark it as published and this
-     * call will return null (until a call to generateFallbackKey is made)
+     * call will return null (until a call to generateFallbackKey is made).
      */
     fun getFallbackKey(): MutableMap<String, MutableMap<String, String>>? {
         try {
@@ -198,7 +197,7 @@ internal class MXOlmDevice @Inject constructor(
     }
 
     /**
-     * Release the instance
+     * Release the instance.
      */
     fun release() {
         olmUtility?.releaseUtility()
@@ -241,7 +240,7 @@ internal class MXOlmDevice @Inject constructor(
     }
 
     /**
-     * Generate some new one-time keys
+     * Generate some new one-time keys.
      *
      * @param numKeys number of keys to generate
      */
@@ -331,14 +330,6 @@ internal class MXOlmDevice @Inject constructor(
                 Timber.tag(loggerTag.value).e(e, "## createInboundSession() : removeOneTimeKeys failed")
             }
 
-            Timber.tag(loggerTag.value).v("## createInboundSession() : ciphertext: $ciphertext")
-            try {
-                val sha256 = olmUtility!!.sha256(URLEncoder.encode(ciphertext, "utf-8"))
-                Timber.tag(loggerTag.value).v("## createInboundSession() :ciphertext: SHA256: $sha256")
-            } catch (e: Exception) {
-                Timber.tag(loggerTag.value).e(e, "## createInboundSession() :ciphertext: cannot encode ciphertext")
-            }
-
             val olmMessage = OlmMessage()
             olmMessage.mCipherText = ciphertext
             olmMessage.mType = messageType.toLong()
@@ -589,6 +580,13 @@ internal class MXOlmDevice @Inject constructor(
 
     //  Inbound group session
 
+    sealed interface AddSessionResult {
+        data class Imported(val ratchetIndex: Int) : AddSessionResult
+        abstract class Failure : AddSessionResult
+        object NotImported : Failure()
+        data class NotImportedHigherIndex(val newIndex: Int) : Failure()
+    }
+
     /**
      * Add an inbound group session to the session store.
      *
@@ -607,7 +605,7 @@ internal class MXOlmDevice @Inject constructor(
                                senderKey: String,
                                forwardingCurve25519KeyChain: List<String>,
                                keysClaimed: Map<String, String>,
-                               exportFormat: Boolean): Boolean {
+                               exportFormat: Boolean): AddSessionResult {
         val candidateSession = OlmInboundGroupSessionWrapper2(sessionKey, exportFormat)
         val existingSessionHolder = tryOrNull { getInboundGroupSession(sessionId, senderKey, roomId) }
         val existingSession = existingSessionHolder?.wrapper
@@ -615,7 +613,7 @@ internal class MXOlmDevice @Inject constructor(
         if (existingSession != null) {
             Timber.tag(loggerTag.value).d("## addInboundGroupSession() check if known session is better than candidate session")
             try {
-                val existingFirstKnown = existingSession.firstKnownIndex ?: return false.also {
+                val existingFirstKnown = existingSession.firstKnownIndex ?: return AddSessionResult.NotImported.also {
                     // This is quite unexpected, could throw if native was released?
                     Timber.tag(loggerTag.value).e("## addInboundGroupSession() null firstKnownIndex on existing session")
                     candidateSession.olmInboundGroupSession?.releaseSession()
@@ -626,12 +624,12 @@ internal class MXOlmDevice @Inject constructor(
                 if (newKnownFirstIndex != null && existingFirstKnown <= newKnownFirstIndex) {
                     Timber.tag(loggerTag.value).d("## addInboundGroupSession() : ignore session our is better $senderKey/$sessionId")
                     candidateSession.olmInboundGroupSession?.releaseSession()
-                    return false
+                    return AddSessionResult.NotImportedHigherIndex(newKnownFirstIndex.toInt())
                 }
             } catch (failure: Throwable) {
                 Timber.tag(loggerTag.value).e("## addInboundGroupSession() Failed to add inbound: ${failure.localizedMessage}")
                 candidateSession.olmInboundGroupSession?.releaseSession()
-                return false
+                return AddSessionResult.NotImported
             }
         }
 
@@ -641,19 +639,19 @@ internal class MXOlmDevice @Inject constructor(
         val candidateOlmInboundSession = candidateSession.olmInboundGroupSession
         if (null == candidateOlmInboundSession) {
             Timber.tag(loggerTag.value).e("## addInboundGroupSession : invalid session <null>")
-            return false
+            return AddSessionResult.NotImported
         }
 
         try {
             if (candidateOlmInboundSession.sessionIdentifier() != sessionId) {
                 Timber.tag(loggerTag.value).e("## addInboundGroupSession : ERROR: Mismatched group session ID from senderKey: $senderKey")
                 candidateOlmInboundSession.releaseSession()
-                return false
+                return AddSessionResult.NotImported
             }
         } catch (e: Throwable) {
             candidateOlmInboundSession.releaseSession()
             Timber.tag(loggerTag.value).e(e, "## addInboundGroupSession : sessionIdentifier() failed")
-            return false
+            return AddSessionResult.NotImported
         }
 
         candidateSession.senderKey = senderKey
@@ -667,7 +665,7 @@ internal class MXOlmDevice @Inject constructor(
             inboundGroupSessionStore.storeInBoundGroupSession(InboundGroupSessionHolder(candidateSession), sessionId, senderKey)
         }
 
-        return true
+        return AddSessionResult.Imported(candidateSession.firstKnownIndex?.toInt() ?: 0)
     }
 
     /**
@@ -790,7 +788,7 @@ internal class MXOlmDevice @Inject constructor(
 
                 if (timelineSet.contains(messageIndexKey)) {
                     val reason = String.format(MXCryptoError.DUPLICATE_MESSAGE_INDEX_REASON, decryptResult.mIndex)
-                    Timber.tag(loggerTag.value).e("## decryptGroupMessage() : $reason")
+                    Timber.tag(loggerTag.value).e("## decryptGroupMessage() timelineId=$timeline: $reason")
                     throw MXCryptoError.Base(MXCryptoError.ErrorType.DUPLICATED_MESSAGE_INDEX, reason)
                 }
 
@@ -858,7 +856,7 @@ internal class MXOlmDevice @Inject constructor(
     }
 
     /**
-     * Search an OlmSession
+     * Search an OlmSession.
      *
      * @param theirDeviceIdentityKey the device key
      * @param sessionId              the session Id
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MyDeviceInfoHolder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MyDeviceInfoHolder.kt
index 9798d21576077b553c5f53efdf01b3cefce7d130..3d09c0469ba790e4322c9ded0c0d537a572a6d1a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MyDeviceInfoHolder.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MyDeviceInfoHolder.kt
@@ -34,7 +34,7 @@ internal class MyDeviceInfoHolder @Inject constructor(
 ) {
     // Our device keys
     /**
-     * my device info
+     * my device info.
      */
     val myDevice: CryptoDeviceInfo
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ObjectSigner.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ObjectSigner.kt
index 68dd17324bb6a4b795eafa5cb49fe263c7192e7e..ab562d954a1f520f3b17f6b77b770da8b31337ec 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ObjectSigner.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ObjectSigner.kt
@@ -23,7 +23,7 @@ internal class ObjectSigner @Inject constructor(private val credentials: Credent
                                                 private val olmDevice: MXOlmDevice) {
 
     /**
-     * Sign Object
+     * Sign Object.
      *
      * Example:
      * <pre>
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmSessionStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmSessionStore.kt
index aac6f67aea1ea95dd0aa698b4160865986b5f336..fe280416ea25eea43d5bdf4815fdfd67d0389e77 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmSessionStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmSessionStore.kt
@@ -26,12 +26,12 @@ import javax.inject.Inject
 private val loggerTag = LoggerTag("OlmSessionStore", LoggerTag.CRYPTO)
 
 /**
- * Keep the used olm session in memory and load them from the data layer when needed
- * Access is synchronized for thread safety
+ * Keep the used olm session in memory and load them from the data layer when needed.
+ * Access is synchronized for thread safety.
  */
 internal class OlmSessionStore @Inject constructor(private val store: IMXCryptoStore) {
     /**
-     * map of device key to list of olm sessions (it is possible to have several active sessions with a device)
+     * Map of device key to list of olm sessions (it is possible to have several active sessions with a device).
      */
     private val olmSessions = HashMap<String, MutableList<OlmSessionWrapper>>()
 
@@ -89,7 +89,7 @@ internal class OlmSessionStore @Inject constructor(private val store: IMXCryptoS
     }
 
     /**
-     * Retrieve the last used sessionId, regarding `lastReceivedMessageTs`, or null if no session exist
+     * Retrieve the last used sessionId, regarding `lastReceivedMessageTs`, or null if no session exist.
      *
      * @param deviceKey the public key of the other device.
      * @return last used sessionId, or null if not found
@@ -110,7 +110,7 @@ internal class OlmSessionStore @Inject constructor(private val store: IMXCryptoS
     }
 
     /**
-     * Release all sessions and clear cache
+     * Release all sessions and clear cache.
      */
     @Synchronized
     fun clear() {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingGossipingRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingGossipingRequest.kt
deleted file mode 100644
index 2438e011029ddc02628e7e41db1ee45b71f5a8c5..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingGossipingRequest.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto
-
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingGossipingRequestState
-
-internal interface OutgoingGossipingRequest {
-    val recipients: Map<String, List<String>>
-    val requestId: String
-    val state: OutgoingGossipingRequestState
-    // transaction id for the cancellation, if any
-    // var cancellationTxnId: String?
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingGossipingRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingGossipingRequestManager.kt
deleted file mode 100755
index e6f6ac505310250970da3e089484d8884f2c83c2..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingGossipingRequestManager.kt
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingGossipingRequestState
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingRoomKeyRequest
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.createUniqueTxnId
-import org.matrix.android.sdk.internal.crypto.util.RequestIdHelper
-import org.matrix.android.sdk.internal.di.SessionId
-import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
-import timber.log.Timber
-import javax.inject.Inject
-
-@SessionScope
-internal class OutgoingGossipingRequestManager @Inject constructor(
-        @SessionId private val sessionId: String,
-        private val cryptoStore: IMXCryptoStore,
-        private val coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val cryptoCoroutineScope: CoroutineScope,
-        private val gossipingWorkManager: GossipingWorkManager) {
-
-    /**
-     * Send off a room key request, if we haven't already done so.
-     *
-     *
-     * The `requestBody` is compared (with a deep-equality check) against
-     * previous queued or sent requests and if it matches, no change is made.
-     * Otherwise, a request is added to the pending list, and a job is started
-     * in the background to send it.
-     *
-     * @param requestBody requestBody
-     * @param recipients  recipients
-     */
-    fun sendRoomKeyRequest(requestBody: RoomKeyRequestBody, recipients: Map<String, List<String>>) {
-        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
-            cryptoStore.getOrAddOutgoingRoomKeyRequest(requestBody, recipients)?.let {
-                // Don't resend if it's already done, you need to cancel first (reRequest)
-                if (it.state == OutgoingGossipingRequestState.SENDING || it.state == OutgoingGossipingRequestState.SENT) {
-                    Timber.v("## CRYPTO - GOSSIP sendOutgoingRoomKeyRequest() : we already request for that session: $it")
-                    return@launch
-                }
-
-                sendOutgoingGossipingRequest(it)
-            }
-        }
-    }
-
-    fun sendSecretShareRequest(secretName: String, recipients: Map<String, List<String>>) {
-        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
-            // A bit dirty, but for better stability give other party some time to mark
-            // devices trusted :/
-            delay(1500)
-            cryptoStore.getOrAddOutgoingSecretShareRequest(secretName, recipients)?.let {
-                // TODO check if there is already one that is being sent?
-                if (it.state == OutgoingGossipingRequestState.SENDING
-                /**|| it.state == OutgoingGossipingRequestState.SENT*/
-                ) {
-                    Timber.v("## CRYPTO - GOSSIP sendSecretShareRequest() : we are already sending for that session: $it")
-                    return@launch
-                }
-
-                sendOutgoingGossipingRequest(it)
-            }
-        }
-    }
-
-    /**
-     * Cancel room key requests, if any match the given details
-     *
-     * @param requestBody requestBody
-     */
-    fun cancelRoomKeyRequest(requestBody: RoomKeyRequestBody) {
-        cryptoCoroutineScope.launch(coroutineDispatchers.computation) {
-            cancelRoomKeyRequest(requestBody, false)
-        }
-    }
-
-    /**
-     * Cancel room key requests, if any match the given details, and resend
-     *
-     * @param requestBody requestBody
-     */
-    fun resendRoomKeyRequest(requestBody: RoomKeyRequestBody) {
-        cryptoCoroutineScope.launch(coroutineDispatchers.computation) {
-            cancelRoomKeyRequest(requestBody, true)
-        }
-    }
-
-    /**
-     * Cancel room key requests, if any match the given details, and resend
-     *
-     * @param requestBody requestBody
-     * @param andResend   true to resend the key request
-     */
-    private fun cancelRoomKeyRequest(requestBody: RoomKeyRequestBody, andResend: Boolean) {
-        val req = cryptoStore.getOutgoingRoomKeyRequest(requestBody) // no request was made for this key
-                ?: return Unit.also {
-                    Timber.v("## CRYPTO - GOSSIP cancelRoomKeyRequest() Unknown request $requestBody")
-                }
-
-        sendOutgoingRoomKeyRequestCancellation(req, andResend)
-    }
-
-    /**
-     * Send the outgoing key request.
-     *
-     * @param request the request
-     */
-    private fun sendOutgoingGossipingRequest(request: OutgoingGossipingRequest) {
-        Timber.v("## CRYPTO - GOSSIP sendOutgoingGossipingRequest() : Requesting keys $request")
-
-        val params = SendGossipRequestWorker.Params(
-                sessionId = sessionId,
-                keyShareRequest = request as? OutgoingRoomKeyRequest,
-                secretShareRequest = request as? OutgoingSecretRequest,
-                txnId = createUniqueTxnId()
-        )
-        cryptoStore.updateOutgoingGossipingRequestState(request.requestId, OutgoingGossipingRequestState.SENDING)
-        val workRequest = gossipingWorkManager.createWork<SendGossipRequestWorker>(WorkerParamsFactory.toData(params), true)
-        gossipingWorkManager.postWork(workRequest)
-    }
-
-    /**
-     * Given a OutgoingRoomKeyRequest, cancel it and delete the request record
-     *
-     * @param request the request
-     */
-    private fun sendOutgoingRoomKeyRequestCancellation(request: OutgoingRoomKeyRequest, resend: Boolean = false) {
-        Timber.v("## CRYPTO - sendOutgoingRoomKeyRequestCancellation $request")
-        val params = CancelGossipRequestWorker.Params.fromRequest(sessionId, request)
-        cryptoStore.updateOutgoingGossipingRequestState(request.requestId, OutgoingGossipingRequestState.CANCELLING)
-
-        val workRequest = gossipingWorkManager.createWork<CancelGossipRequestWorker>(WorkerParamsFactory.toData(params), true)
-        gossipingWorkManager.postWork(workRequest)
-
-        if (resend) {
-            val reSendParams = SendGossipRequestWorker.Params(
-                    sessionId = sessionId,
-                    keyShareRequest = request.copy(requestId = RequestIdHelper.createUniqueRequestId()),
-                    txnId = createUniqueTxnId()
-            )
-            val reSendWorkRequest = gossipingWorkManager.createWork<SendGossipRequestWorker>(WorkerParamsFactory.toData(reSendParams), true)
-            gossipingWorkManager.postWork(reSendWorkRequest)
-        }
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt
new file mode 100755
index 0000000000000000000000000000000000000000..d7652d07713b60ebf71fb6aae07cae5cf9ff2cf3
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2020 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.internal.crypto
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.asCoroutineDispatcher
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
+import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
+import org.matrix.android.sdk.api.crypto.MXCryptoConfig
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.logger.LoggerTag
+import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest
+import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState
+import org.matrix.android.sdk.api.session.crypto.model.GossipingToDeviceObject
+import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
+import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
+import org.matrix.android.sdk.api.session.crypto.model.RoomKeyShareRequest
+import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
+import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
+import org.matrix.android.sdk.api.session.events.model.toModel
+import org.matrix.android.sdk.api.util.fromBase64
+import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
+import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
+import org.matrix.android.sdk.internal.di.SessionId
+import org.matrix.android.sdk.internal.di.UserId
+import org.matrix.android.sdk.internal.session.SessionScope
+import org.matrix.android.sdk.internal.task.SemaphoreCoroutineSequencer
+import timber.log.Timber
+import java.util.Stack
+import java.util.concurrent.Executors
+import javax.inject.Inject
+import kotlin.system.measureTimeMillis
+
+private val loggerTag = LoggerTag("OutgoingKeyRequestManager", LoggerTag.CRYPTO)
+
+/**
+ * This class is responsible for sending key requests to other devices when a message failed to decrypt.
+ * It's lifecycle is based on the sync pulse:
+ *    - You can post queries for session, or report when you got a session
+ *    - At the end of the sync (onSyncComplete) it will then process all the posted request and send to devices
+ * If a request failed it will be retried at the end of the next sync
+ */
+@SessionScope
+internal class OutgoingKeyRequestManager @Inject constructor(
+        @SessionId private val sessionId: String,
+        @UserId private val myUserId: String,
+        private val cryptoStore: IMXCryptoStore,
+        private val coroutineDispatchers: MatrixCoroutineDispatchers,
+        private val cryptoConfig: MXCryptoConfig,
+        private val inboundGroupSessionStore: InboundGroupSessionStore,
+        private val sendToDeviceTask: SendToDeviceTask,
+        private val deviceListManager: DeviceListManager,
+        private val perSessionBackupQueryRateLimiter: PerSessionBackupQueryRateLimiter) {
+
+    private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
+    private val outgoingRequestScope = CoroutineScope(SupervisorJob() + dispatcher)
+    private val sequencer = SemaphoreCoroutineSequencer()
+
+    // We only have one active key request per session, so we don't request if it's already requested
+    // But it could make sense to check more the backup, as it's evolving.
+    // We keep a stack as we consider that the key requested last is more likely to be on screen?
+    private val requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup = Stack<Pair<String, String>>()
+
+    fun requestKeyForEvent(event: Event, force: Boolean) {
+        val (targets, body) = getRoomKeyRequestTargetForEvent(event) ?: return
+        val index = ratchetIndexForMessage(event) ?: 0
+        postRoomKeyRequest(body, targets, index, force)
+    }
+
+    private fun getRoomKeyRequestTargetForEvent(event: Event): Pair<Map<String, List<String>>, RoomKeyRequestBody>? {
+        val sender = event.senderId ?: return null
+        val encryptedEventContent = event.content.toModel<EncryptedEventContent>() ?: return null.also {
+            Timber.tag(loggerTag.value).e("getRoomKeyRequestTargetForEvent Failed to re-request key, null content")
+        }
+        if (encryptedEventContent.algorithm != MXCRYPTO_ALGORITHM_MEGOLM) return null
+
+        val senderDevice = encryptedEventContent.deviceId
+        val recipients = if (cryptoConfig.limitRoomKeyRequestsToMyDevices) {
+            mapOf(
+                    myUserId to listOf("*")
+            )
+        } else {
+            if (event.senderId == myUserId) {
+                mapOf(
+                        myUserId to listOf("*")
+                )
+            } else {
+                // for the case where you share the key with a device that has a broken olm session
+                // The other user might Re-shares a megolm session key with devices if the key has already been
+                // sent to them.
+                mapOf(
+                        myUserId to listOf("*"),
+
+                        // We might not have deviceId in the future due to https://github.com/matrix-org/matrix-spec-proposals/pull/3700
+                        // so in this case query to all
+                        sender to listOf(senderDevice ?: "*")
+                )
+            }
+        }
+
+        val requestBody = RoomKeyRequestBody(
+                roomId = event.roomId,
+                algorithm = encryptedEventContent.algorithm,
+                senderKey = encryptedEventContent.senderKey,
+                sessionId = encryptedEventContent.sessionId
+        )
+        return recipients to requestBody
+    }
+
+    private fun ratchetIndexForMessage(event: Event): Int? {
+        val encryptedContent = event.content.toModel<EncryptedEventContent>() ?: return null
+        if (encryptedContent.algorithm != MXCRYPTO_ALGORITHM_MEGOLM) return null
+        return encryptedContent.ciphertext?.fromBase64()?.inputStream()?.reader()?.let {
+            tryOrNull {
+                val megolmVersion = it.read()
+                if (megolmVersion != 3) return@tryOrNull null
+                /** Int tag */
+                if (it.read() != 8) return@tryOrNull null
+                it.read()
+            }
+        }
+    }
+
+    fun postRoomKeyRequest(requestBody: RoomKeyRequestBody, recipients: Map<String, List<String>>, fromIndex: Int, force: Boolean = false) {
+        outgoingRequestScope.launch {
+            sequencer.post {
+                internalQueueRequest(requestBody, recipients, fromIndex, force)
+            }
+        }
+    }
+
+    /**
+     * Typically called when we the session as been imported or received meanwhile.
+     */
+    fun postCancelRequestForSessionIfNeeded(sessionId: String, roomId: String, senderKey: String, fromIndex: Int) {
+        outgoingRequestScope.launch {
+            sequencer.post {
+                internalQueueCancelRequest(sessionId, roomId, senderKey, fromIndex)
+            }
+        }
+    }
+
+    fun onSelfCrossSigningTrustChanged(newTrust: Boolean) {
+        if (newTrust) {
+            // we were previously not cross signed, but we are now
+            // so there is now more chances to get better replies for existing request
+            // Let's forget about sent request so that next time we try to decrypt we will resend requests
+            // We don't resend all because we don't want to generate a bulk of traffic
+            outgoingRequestScope.launch {
+                sequencer.post {
+                    cryptoStore.deleteOutgoingRoomKeyRequestInState(OutgoingRoomKeyRequestState.SENT)
+                }
+
+                sequencer.post {
+                    delay(1000)
+                    perSessionBackupQueryRateLimiter.refreshBackupInfoIfNeeded(true)
+                }
+            }
+        }
+    }
+
+    fun onRoomKeyForwarded(sessionId: String,
+                           algorithm: String,
+                           roomId: String,
+                           senderKey: String,
+                           fromDevice: String?,
+                           fromIndex: Int,
+                           event: Event) {
+        Timber.tag(loggerTag.value).d("Key forwarded for $sessionId from ${event.senderId}|$fromDevice at index $fromIndex")
+        outgoingRequestScope.launch {
+            sequencer.post {
+                cryptoStore.updateOutgoingRoomKeyReply(
+                        roomId = roomId,
+                        sessionId = sessionId,
+                        algorithm = algorithm,
+                        senderKey = senderKey,
+                        fromDevice = fromDevice,
+                        // strip out encrypted stuff as it's just a trail?
+                        event = event.copy(
+                                type = event.getClearType(),
+                                content = mapOf(
+                                        "chain_index" to fromIndex
+                                )
+                        )
+                )
+            }
+        }
+    }
+
+    fun onRoomKeyWithHeld(sessionId: String,
+                          algorithm: String,
+                          roomId: String,
+                          senderKey: String,
+                          fromDevice: String?,
+                          event: Event) {
+        outgoingRequestScope.launch {
+            sequencer.post {
+                Timber.tag(loggerTag.value).d("Withheld received for $sessionId from ${event.senderId}|$fromDevice")
+                Timber.tag(loggerTag.value).v("Withheld content ${event.getClearContent()}")
+
+                // We want to store withheld code from the sender of the message (owner of the megolm session), not from
+                // other devices that might gossip the key. If not the initial reason might be overridden
+                // by a request to one of our session.
+                event.getClearContent().toModel<RoomKeyWithHeldContent>()?.let { withheld ->
+                    withContext(coroutineDispatchers.crypto) {
+                        tryOrNull {
+                            deviceListManager.downloadKeys(listOf(event.senderId ?: ""), false)
+                        }
+                        cryptoStore.getUserDeviceList(event.senderId ?: "")
+                                .also { devices ->
+                                    Timber.tag(loggerTag.value)
+                                            .v("Withheld Devices for ${event.senderId} are ${devices.orEmpty().joinToString { it.identityKey() ?: "" }}")
+                                }
+                                ?.firstOrNull {
+                                    it.identityKey() == senderKey
+                                }
+                    }.also {
+                        Timber.tag(loggerTag.value).v("Withheld device for sender key $senderKey is from ${it?.shortDebugString()}")
+                    }?.let {
+                        if (it.userId == event.senderId) {
+                            if (fromDevice != null) {
+                                if (it.deviceId == fromDevice) {
+                                    Timber.tag(loggerTag.value).v("Storing sender Withheld code ${withheld.code} for ${withheld.sessionId}")
+                                    cryptoStore.addWithHeldMegolmSession(withheld)
+                                }
+                            } else {
+                                Timber.tag(loggerTag.value).v("Storing sender Withheld code ${withheld.code} for ${withheld.sessionId}")
+                                cryptoStore.addWithHeldMegolmSession(withheld)
+                            }
+                        }
+                    }
+                }
+
+                // Here we store the replies from a given request
+                cryptoStore.updateOutgoingRoomKeyReply(
+                        roomId = roomId,
+                        sessionId = sessionId,
+                        algorithm = algorithm,
+                        senderKey = senderKey,
+                        fromDevice = fromDevice,
+                        event = event
+                )
+            }
+        }
+    }
+
+    /**
+     * Should be called after a sync, ideally if no catchup sync needed (as keys might arrive in those).
+     */
+    fun requireProcessAllPendingKeyRequests() {
+        outgoingRequestScope.launch {
+            sequencer.post {
+                internalProcessPendingKeyRequests()
+            }
+        }
+    }
+
+    private fun internalQueueCancelRequest(sessionId: String, roomId: String, senderKey: String, localKnownChainIndex: Int) {
+        // do we have known requests for that session??
+        Timber.tag(loggerTag.value).v("Cancel Key Request if needed for $sessionId")
+        val knownRequest = cryptoStore.getOutgoingRoomKeyRequest(
+                algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
+                roomId = roomId,
+                sessionId = sessionId,
+                senderKey = senderKey
+        )
+        if (knownRequest.isEmpty()) return Unit.also {
+            Timber.tag(loggerTag.value).v("Handle Cancel Key Request for $sessionId -- Was not currently requested")
+        }
+        if (knownRequest.size > 1) {
+            // It's worth logging, there should be only one
+            Timber.tag(loggerTag.value).w("Found multiple requests for same sessionId $sessionId")
+        }
+        knownRequest.forEach { request ->
+            when (request.state) {
+                OutgoingRoomKeyRequestState.UNSENT                               -> {
+                    if (request.fromIndex >= localKnownChainIndex) {
+                        // we have a good index we can cancel
+                        cryptoStore.deleteOutgoingRoomKeyRequest(request.requestId)
+                    }
+                }
+                OutgoingRoomKeyRequestState.SENT                                 -> {
+                    // It was already sent, and index satisfied we can cancel
+                    if (request.fromIndex >= localKnownChainIndex) {
+                        cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING)
+                    }
+                }
+                OutgoingRoomKeyRequestState.CANCELLATION_PENDING                 -> {
+                    // It is already marked to be cancelled
+                }
+                OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> {
+                    if (request.fromIndex >= localKnownChainIndex) {
+                        // we just want to cancel now
+                        cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING)
+                    }
+                }
+                OutgoingRoomKeyRequestState.SENT_THEN_CANCELED                   -> {
+                    // was already canceled
+                    // if we need a better index, should we resend?
+                }
+            }
+        }
+    }
+
+    fun close() {
+        try {
+            outgoingRequestScope.cancel("User Terminate")
+            requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup.clear()
+        } catch (failure: Throwable) {
+            Timber.tag(loggerTag.value).w("Failed to shutDown request manager")
+        }
+    }
+
+    private fun internalQueueRequest(requestBody: RoomKeyRequestBody, recipients: Map<String, List<String>>, fromIndex: Int, force: Boolean) {
+        if (!cryptoStore.isKeyGossipingEnabled()) {
+            // we might want to try backup?
+            if (requestBody.roomId != null && requestBody.sessionId != null) {
+                requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup.push(requestBody.roomId to requestBody.sessionId)
+            }
+            Timber.tag(loggerTag.value).d("discarding request for ${requestBody.sessionId} as gossiping is disabled")
+            return
+        }
+
+        Timber.tag(loggerTag.value).d("Queueing key request for ${requestBody.sessionId} force:$force")
+        val existing = cryptoStore.getOutgoingRoomKeyRequest(requestBody)
+        Timber.tag(loggerTag.value).v("Queueing key request exiting is ${existing?.state}")
+        when (existing?.state) {
+            null                                                             -> {
+                // create a new one
+                cryptoStore.getOrAddOutgoingRoomKeyRequest(requestBody, recipients, fromIndex)
+            }
+            OutgoingRoomKeyRequestState.UNSENT                               -> {
+                // nothing it's new or not yet handled
+            }
+            OutgoingRoomKeyRequestState.SENT                                 -> {
+                // it was already requested
+                Timber.tag(loggerTag.value).d("The session ${requestBody.sessionId} is already requested")
+                if (force) {
+                    // update to UNSENT
+                    Timber.tag(loggerTag.value).d(".. force to request  ${requestBody.sessionId}")
+                    cryptoStore.updateOutgoingRoomKeyRequestState(existing.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND)
+                } else {
+                    if (existing.roomId != null && existing.sessionId != null) {
+                        requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup.push(existing.roomId to existing.sessionId)
+                    }
+                }
+            }
+            OutgoingRoomKeyRequestState.CANCELLATION_PENDING                 -> {
+                // request is canceled only if I got the keys so what to do here...
+                if (force) {
+                    cryptoStore.updateOutgoingRoomKeyRequestState(existing.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND)
+                }
+            }
+            OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> {
+                // It's already going to resend
+            }
+            OutgoingRoomKeyRequestState.SENT_THEN_CANCELED                   -> {
+                if (force) {
+                    cryptoStore.deleteOutgoingRoomKeyRequest(existing.requestId)
+                    cryptoStore.getOrAddOutgoingRoomKeyRequest(requestBody, recipients, fromIndex)
+                }
+            }
+        }
+
+        if (existing != null && existing.fromIndex >= fromIndex) {
+            // update the required index
+            cryptoStore.updateOutgoingRoomKeyRequiredIndex(existing.requestId, fromIndex)
+        }
+    }
+
+    private suspend fun internalProcessPendingKeyRequests() {
+        val toProcess = cryptoStore.getOutgoingRoomKeyRequests(OutgoingRoomKeyRequestState.pendingStates())
+        Timber.tag(loggerTag.value).v("Processing all pending key requests (found ${toProcess.size} pending)")
+
+        measureTimeMillis {
+            toProcess.forEach {
+                when (it.state) {
+                    OutgoingRoomKeyRequestState.UNSENT                               -> handleUnsentRequest(it)
+                    OutgoingRoomKeyRequestState.CANCELLATION_PENDING                 -> handleRequestToCancel(it)
+                    OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> handleRequestToCancelWillResend(it)
+                    OutgoingRoomKeyRequestState.SENT_THEN_CANCELED,
+                    OutgoingRoomKeyRequestState.SENT                                 -> {
+                        // these are filtered out
+                    }
+                }
+            }
+        }.let {
+            Timber.tag(loggerTag.value).v("Finish processing pending key request in $it ms")
+        }
+
+        val maxBackupCallsBySync = 60
+        var currentCalls = 0
+        measureTimeMillis {
+            while (requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup.isNotEmpty() && currentCalls < maxBackupCallsBySync) {
+                requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup.pop().let { (roomId, sessionId) ->
+                    // we want to rate limit that somehow :/
+                    perSessionBackupQueryRateLimiter.tryFromBackupIfPossible(sessionId, roomId)
+                }
+                currentCalls++
+            }
+        }.let {
+            Timber.tag(loggerTag.value).v("Finish querying backup in $it ms")
+        }
+    }
+
+    private suspend fun handleUnsentRequest(request: OutgoingKeyRequest) {
+        // In order to avoid generating to_device traffic, we can first check if the key is backed up
+        Timber.tag(loggerTag.value).v("Handling unsent request for megolm session ${request.sessionId} in ${request.roomId}")
+        val sessionId = request.sessionId ?: return
+        val roomId = request.roomId ?: return
+        if (perSessionBackupQueryRateLimiter.tryFromBackupIfPossible(sessionId, roomId)) {
+            // let's see what's the index
+            val knownIndex = tryOrNull {
+                inboundGroupSessionStore.getInboundGroupSession(sessionId, request.requestBody?.senderKey ?: "")?.wrapper?.firstKnownIndex
+            }
+            if (knownIndex != null && knownIndex <= request.fromIndex) {
+                // we found the key in backup with good enough index, so we can just mark as cancelled, no need to send request
+                Timber.tag(loggerTag.value).v("Megolm session $sessionId successfully restored from backup, do not send request")
+                cryptoStore.deleteOutgoingRoomKeyRequest(request.requestId)
+                return
+            }
+        }
+
+        // we need to send the request
+        val toDeviceContent = RoomKeyShareRequest(
+                requestingDeviceId = cryptoStore.getDeviceId(),
+                requestId = request.requestId,
+                action = GossipingToDeviceObject.ACTION_SHARE_REQUEST,
+                body = request.requestBody
+        )
+        val contentMap = MXUsersDevicesMap<Any>()
+        request.recipients.forEach { userToDeviceMap ->
+            userToDeviceMap.value.forEach { deviceId ->
+                contentMap.setObject(userToDeviceMap.key, deviceId, toDeviceContent)
+            }
+        }
+
+        val params = SendToDeviceTask.Params(
+                eventType = EventType.ROOM_KEY_REQUEST,
+                contentMap = contentMap,
+                transactionId = request.requestId
+        )
+        try {
+            withContext(coroutineDispatchers.io) {
+                sendToDeviceTask.executeRetry(params, 3)
+            }
+            Timber.tag(loggerTag.value).d("Key request sent for $sessionId in room $roomId to ${request.recipients}")
+            // The request was sent, so update state
+            cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.SENT)
+            // TODO update the audit trail
+        } catch (failure: Throwable) {
+            Timber.tag(loggerTag.value).v("Failed to request $sessionId targets:${request.recipients}")
+        }
+    }
+
+    private suspend fun handleRequestToCancel(request: OutgoingKeyRequest): Boolean {
+        Timber.tag(loggerTag.value).v("handleRequestToCancel for megolm session ${request.sessionId}")
+        // we have to cancel this
+        val toDeviceContent = RoomKeyShareRequest(
+                requestingDeviceId = cryptoStore.getDeviceId(),
+                requestId = request.requestId,
+                action = GossipingToDeviceObject.ACTION_SHARE_CANCELLATION
+        )
+        val contentMap = MXUsersDevicesMap<Any>()
+        request.recipients.forEach { userToDeviceMap ->
+            userToDeviceMap.value.forEach { deviceId ->
+                contentMap.setObject(userToDeviceMap.key, deviceId, toDeviceContent)
+            }
+        }
+
+        val params = SendToDeviceTask.Params(
+                eventType = EventType.ROOM_KEY_REQUEST,
+                contentMap = contentMap,
+                transactionId = request.requestId
+        )
+        return try {
+            withContext(coroutineDispatchers.io) {
+                sendToDeviceTask.executeRetry(params, 3)
+            }
+            // The request cancellation was sent, we don't delete yet because we want
+            // to keep trace of the sent replies
+            cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.SENT_THEN_CANCELED)
+            true
+        } catch (failure: Throwable) {
+            Timber.tag(loggerTag.value).v("Failed to cancel request ${request.requestId} for session $sessionId targets:${request.recipients}")
+            false
+        }
+    }
+
+    private suspend fun handleRequestToCancelWillResend(request: OutgoingKeyRequest) {
+        if (handleRequestToCancel(request)) {
+            // this will create a new unsent request with no replies that will be process in the following call
+            cryptoStore.deleteOutgoingRoomKeyRequest(request.requestId)
+            request.requestBody?.let { cryptoStore.getOrAddOutgoingRoomKeyRequest(it, request.recipients, request.fromIndex) }
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingSecretRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingSecretRequest.kt
deleted file mode 100755
index 2ba2f5c817add137c63fe7fdabaf9095de928026..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingSecretRequest.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto
-
-import com.squareup.moshi.JsonClass
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingGossipingRequestState
-
-/**
- * Represents an outgoing room key request
- */
-@JsonClass(generateAdapter = true)
-internal class OutgoingSecretRequest(
-        // Secret Name
-        val secretName: String?,
-        // list of recipients for the request
-        override var recipients: Map<String, List<String>>,
-        // Unique id for this request. Used for both
-        // an id within the request for later pairing with a cancellation, and for
-        // the transaction id when sending the to_device messages to our local
-        override var requestId: String,
-        // current state of this request
-        override var state: OutgoingGossipingRequestState) : OutgoingGossipingRequest {
-
-    // transaction id for the cancellation, if any
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PerSessionBackupQueryRateLimiter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PerSessionBackupQueryRateLimiter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5f62e7be9dbd5839d35fe2c61e93cd078d0303c9
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PerSessionBackupQueryRateLimiter.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.internal.crypto
+
+import dagger.Lazy
+import kotlinx.coroutines.withContext
+import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
+import org.matrix.android.sdk.api.logger.LoggerTag
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
+import org.matrix.android.sdk.api.session.crypto.keysbackup.SavedKeyBackupKeyInfo
+import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
+import org.matrix.android.sdk.api.util.awaitCallback
+import org.matrix.android.sdk.internal.crypto.keysbackup.DefaultKeysBackupService
+import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
+import org.matrix.android.sdk.internal.util.time.Clock
+import timber.log.Timber
+import javax.inject.Inject
+
+// I keep the same name as OutgoingGossipingRequestManager to ease filtering of logs
+private val loggerTag = LoggerTag("OutgoingGossipingRequestManager", LoggerTag.CRYPTO)
+
+/**
+ * Used to try to get the key for UISI messages before sending room key request.
+ * We are adding some rate limiting to avoid querying too much for a key not in backup.
+ * Nonetheless the backup can be updated so we might want to retry from time to time.
+ */
+internal class PerSessionBackupQueryRateLimiter @Inject constructor(
+        private val coroutineDispatchers: MatrixCoroutineDispatchers,
+        private val keysBackupService: Lazy<DefaultKeysBackupService>,
+        private val cryptoStore: IMXCryptoStore,
+        private val clock: Clock,
+) {
+
+    companion object {
+        const val MIN_TRY_BACKUP_PERIOD_MILLIS = 60 * 60_000 // 1 hour
+    }
+
+    data class Info(
+            val megolmSessionId: String,
+            val roomId: String
+    )
+
+    data class LastTry(
+            val backupVersion: String,
+            val timestamp: Long
+    )
+
+    /**
+     * Remember what we already tried (a key not in backup or some server issue).
+     * We might want to retry from time to time as the backup could have been updated.
+     */
+    private val lastFailureMap = mutableMapOf<Info, LastTry>()
+
+    private var backupVersion: KeysVersionResult? = null
+    private var savedKeyBackupKeyInfo: SavedKeyBackupKeyInfo? = null
+    var backupWasCheckedFromServer: Boolean = false
+    val now = clock.epochMillis()
+
+    fun refreshBackupInfoIfNeeded(force: Boolean = false) {
+        if (backupWasCheckedFromServer && !force) return
+        Timber.tag(loggerTag.value).v("Checking if can access a backup")
+        backupWasCheckedFromServer = true
+        val knownBackupSecret = cryptoStore.getKeyBackupRecoveryKeyInfo()
+                ?: return Unit.also {
+                    Timber.tag(loggerTag.value).v("We don't have the backup secret!")
+                }
+        this.backupVersion = keysBackupService.get().keysBackupVersion
+        this.savedKeyBackupKeyInfo = knownBackupSecret
+    }
+
+    suspend fun tryFromBackupIfPossible(sessionId: String, roomId: String): Boolean {
+        Timber.tag(loggerTag.value).v("tryFromBackupIfPossible for session:$sessionId in $roomId")
+        refreshBackupInfoIfNeeded()
+        val currentVersion = backupVersion
+        if (savedKeyBackupKeyInfo?.version == null ||
+                currentVersion == null ||
+                currentVersion.version != savedKeyBackupKeyInfo?.version) {
+            // We can't access the backup
+            Timber.tag(loggerTag.value).v("Can't get backup version info")
+            return false
+        }
+        val cacheKey = Info(sessionId, roomId)
+        val lastTry = lastFailureMap[cacheKey]
+        val shouldQuery =
+                lastTry == null ||
+                        lastTry.backupVersion != currentVersion.version ||
+                        (now - lastTry.timestamp) > MIN_TRY_BACKUP_PERIOD_MILLIS
+
+        if (!shouldQuery) return false
+
+        val successfullyImported = withContext(coroutineDispatchers.io) {
+            try {
+                awaitCallback<ImportRoomKeysResult> {
+                    keysBackupService.get().restoreKeysWithRecoveryKey(
+                            currentVersion,
+                            savedKeyBackupKeyInfo?.recoveryKey ?: "",
+                            roomId,
+                            sessionId,
+                            null,
+                            it
+                    )
+                }.successfullyNumberOfImportedKeys
+            } catch (failure: Throwable) {
+                // Fail silently
+                Timber.tag(loggerTag.value).v("getFromBackup failed ${failure.localizedMessage}")
+                0
+            }
+        }
+        if (successfullyImported == 1) {
+            Timber.tag(loggerTag.value).v("Found key in backup session:$sessionId in $roomId")
+            lastFailureMap.remove(cacheKey)
+            return true
+        } else {
+            Timber.tag(loggerTag.value).v("Failed to find key in backup session:$sessionId in $roomId")
+            lastFailureMap[cacheKey] = LastTry(currentVersion.version, clock.epochMillis())
+            return false
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt
index dab806a5657c159f9e09d64f1745cbf440242d55..c2f494b4b3035b3e118ba8ca3b35edf91faf2d7b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt
@@ -79,7 +79,7 @@ internal class RoomDecryptorProvider @Inject constructor(
                             newSessionListeners.toList().forEach {
                                 try {
                                     it.onNewSession(roomId, senderKey, sessionId)
-                                } catch (e: Throwable) {
+                                } catch (ignore: Throwable) {
                                 }
                             }
                         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt
index ba97d9613303fe844d67087f407d14027ef84141..1a8c160d9c313c8fba72777234193a44dce431a8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt
@@ -16,12 +16,21 @@
 
 package org.matrix.android.sdk.internal.crypto
 
+import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
+import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_OLM
 import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting
+import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory
+import org.matrix.android.sdk.internal.crypto.algorithms.olm.MXOlmEncryptionFactory
+import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import org.matrix.android.sdk.internal.session.SessionScope
 import javax.inject.Inject
 
 @SessionScope
-internal class RoomEncryptorsStore @Inject constructor() {
+internal class RoomEncryptorsStore @Inject constructor(
+        private val cryptoStore: IMXCryptoStore,
+        private val megolmEncryptionFactory: MXMegolmEncryptionFactory,
+        private val olmEncryptionFactory: MXOlmEncryptionFactory,
+) {
 
     // MXEncrypting instance for each room.
     private val roomEncryptors = mutableMapOf<String, IMXEncrypting>()
@@ -34,7 +43,18 @@ internal class RoomEncryptorsStore @Inject constructor() {
 
     fun get(roomId: String): IMXEncrypting? {
         return synchronized(roomEncryptors) {
-            roomEncryptors[roomId]
+            val cache = roomEncryptors[roomId]
+            if (cache != null) {
+                return@synchronized cache
+            } else {
+                val alg: IMXEncrypting? = when (cryptoStore.getRoomAlgorithm(roomId)) {
+                    MXCRYPTO_ALGORITHM_MEGOLM -> megolmEncryptionFactory.create(roomId)
+                    MXCRYPTO_ALGORITHM_OLM    -> olmEncryptionFactory.create(roomId)
+                    else                      -> null
+                }
+                alg?.let { roomEncryptors.put(roomId, it) }
+                return@synchronized alg
+            }
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6fb6914206f9e97000915ab0262117c435278c27
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.internal.crypto
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.withContext
+import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
+import org.matrix.android.sdk.api.auth.data.Credentials
+import org.matrix.android.sdk.api.logger.LoggerTag
+import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
+import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
+import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
+import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
+import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromRecoveryKey
+import org.matrix.android.sdk.api.session.crypto.keyshare.GossipingRequestListener
+import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
+import org.matrix.android.sdk.api.session.crypto.model.SecretShareRequest
+import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.events.model.content.SecretSendEventContent
+import org.matrix.android.sdk.api.session.events.model.toModel
+import org.matrix.android.sdk.api.util.toBase64NoPadding
+import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
+import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
+import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
+import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
+import org.matrix.android.sdk.internal.crypto.tasks.createUniqueTxnId
+import org.matrix.android.sdk.internal.session.SessionScope
+import org.matrix.android.sdk.internal.util.time.Clock
+import timber.log.Timber
+import javax.inject.Inject
+
+private val loggerTag = LoggerTag("SecretShareManager", LoggerTag.CRYPTO)
+
+@SessionScope
+internal class SecretShareManager @Inject constructor(
+        private val credentials: Credentials,
+        private val cryptoStore: IMXCryptoStore,
+        private val cryptoCoroutineScope: CoroutineScope,
+        private val messageEncrypter: MessageEncrypter,
+        private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
+        private val sendToDeviceTask: SendToDeviceTask,
+        private val coroutineDispatchers: MatrixCoroutineDispatchers,
+        private val clock: Clock,
+) {
+
+    companion object {
+        private const val SECRET_SHARE_WINDOW_DURATION = 5 * 60 * 1000 // 5 minutes
+    }
+
+    /**
+     * Secret gossiping only occurs during a limited window period after interactive verification.
+     * We keep track of recent verification in memory for that purpose (no need to persist)
+     */
+    private val recentlyVerifiedDevices = mutableMapOf<String, Long>()
+    private val verifMutex = Mutex()
+
+    /**
+     * Secrets are exchanged as part of interactive verification,
+     * so we can just store in memory.
+     */
+    private val outgoingSecretRequests = mutableListOf<SecretShareRequest>()
+
+    // the listeners
+    private val gossipingRequestListeners: MutableSet<GossipingRequestListener> = HashSet()
+
+    fun addListener(listener: GossipingRequestListener) {
+        synchronized(gossipingRequestListeners) {
+            gossipingRequestListeners.add(listener)
+        }
+    }
+
+    fun removeListener(listener: GossipingRequestListener) {
+        synchronized(gossipingRequestListeners) {
+            gossipingRequestListeners.remove(listener)
+        }
+    }
+
+    /**
+     * Called when a session has been verified.
+     * This information can be used by the manager to decide whether or not to fullfill gossiping requests.
+     * This should be called as fast as possible after a successful self interactive verification
+     */
+    fun onVerificationCompleteForDevice(deviceId: String) {
+        // For now we just keep an in memory cache
+        cryptoCoroutineScope.launch {
+            verifMutex.withLock {
+                recentlyVerifiedDevices[deviceId] = clock.epochMillis()
+            }
+        }
+    }
+
+    suspend fun handleSecretRequest(toDevice: Event) {
+        val request = toDevice.getClearContent().toModel<SecretShareRequest>()
+                ?: return Unit.also {
+                    Timber.tag(loggerTag.value)
+                            .w("handleSecretRequest() : malformed request")
+                }
+
+//            val (action, requestingDeviceId, requestId, secretName) = it
+        val secretName = request.secretName ?: return Unit.also {
+            Timber.tag(loggerTag.value)
+                    .v("handleSecretRequest() : Missing secret name")
+        }
+
+        val userId = toDevice.senderId ?: return Unit.also {
+            Timber.tag(loggerTag.value)
+                    .v("handleSecretRequest() : Missing senderId")
+        }
+
+        if (userId != credentials.userId) {
+            // secrets are only shared between our own devices
+            Timber.tag(loggerTag.value)
+                    .e("Ignoring secret share request from other users $userId")
+            return
+        }
+
+        val deviceId = request.requestingDeviceId
+                ?: return Unit.also {
+                    Timber.tag(loggerTag.value)
+                            .w("handleSecretRequest() : malformed request norequestingDeviceId ")
+                }
+
+        val device = cryptoStore.getUserDevice(credentials.userId, deviceId)
+                ?: return Unit.also {
+                    Timber.tag(loggerTag.value)
+                            .e("Received secret share request from unknown device $deviceId")
+                }
+
+        val isRequestingDeviceTrusted = device.isVerified
+        val isRecentInteractiveVerification = hasBeenVerifiedLessThanFiveMinutesFromNow(device.deviceId)
+        if (isRequestingDeviceTrusted && isRecentInteractiveVerification) {
+            // we can share the secret
+
+            val secretValue = when (secretName) {
+                MASTER_KEY_SSSS_NAME       -> cryptoStore.getCrossSigningPrivateKeys()?.master
+                SELF_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.selfSigned
+                USER_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.user
+                KEYBACKUP_SECRET_SSSS_NAME -> cryptoStore.getKeyBackupRecoveryKeyInfo()?.recoveryKey
+                        ?.let {
+                            extractCurveKeyFromRecoveryKey(it)?.toBase64NoPadding()
+                        }
+                else                       -> null
+            }
+            if (secretValue == null) {
+                Timber.tag(loggerTag.value)
+                        .i("The secret is unknown $secretName, passing to app layer")
+                val toList = synchronized(gossipingRequestListeners) { gossipingRequestListeners.toList() }
+                toList.onEach { listener ->
+                    listener.onSecretShareRequest(request)
+                }
+                return
+            }
+
+            val payloadJson = mapOf(
+                    "type" to EventType.SEND_SECRET,
+                    "content" to mapOf(
+                            "request_id" to request.requestId,
+                            "secret" to secretValue
+                    )
+            )
+
+            // Is it possible that we don't have an olm session?
+            val devicesByUser = mapOf(device.userId to listOf(device))
+            val usersDeviceMap = try {
+                ensureOlmSessionsForDevicesAction.handle(devicesByUser)
+            } catch (failure: Throwable) {
+                Timber.tag(loggerTag.value)
+                        .w("Can't share secret ${request.secretName}: Failed to establish olm session")
+                return
+            }
+
+            val olmSessionResult = usersDeviceMap.getObject(device.userId, device.deviceId)
+            if (olmSessionResult?.sessionId == null) {
+                Timber.tag(loggerTag.value)
+                        .w("secret share: no session with this device $deviceId, probably because there were no one-time keys")
+                return
+            }
+
+            val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(device))
+            val sendToDeviceMap = MXUsersDevicesMap<Any>()
+            sendToDeviceMap.setObject(device.userId, device.deviceId, encodedPayload)
+            val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
+            try {
+                // raise the retries for secret
+                sendToDeviceTask.executeRetry(sendToDeviceParams, 6)
+                Timber.tag(loggerTag.value)
+                        .i("successfully shared secret $secretName to ${device.shortDebugString()}")
+                // TODO add a trail for that in audit logs
+            } catch (failure: Throwable) {
+                Timber.tag(loggerTag.value)
+                        .e(failure, "failed to send shared secret $secretName to ${device.shortDebugString()}")
+            }
+        } else {
+            Timber.tag(loggerTag.value)
+                    .d(" Received secret share request from un-authorised device ${device.deviceId}")
+        }
+    }
+
+    private suspend fun hasBeenVerifiedLessThanFiveMinutesFromNow(deviceId: String): Boolean {
+        val verifTimestamp = verifMutex.withLock {
+            recentlyVerifiedDevices[deviceId]
+        } ?: return false
+
+        val age = clock.epochMillis() - verifTimestamp
+
+        return age < SECRET_SHARE_WINDOW_DURATION
+    }
+
+    suspend fun requestSecretTo(deviceId: String, secretName: String) {
+        val cryptoDeviceInfo = cryptoStore.getUserDevice(credentials.userId, deviceId) ?: return Unit.also {
+            Timber.tag(loggerTag.value)
+                    .d("Can't request secret for $secretName unknown device $deviceId")
+        }
+        val toDeviceContent = SecretShareRequest(
+                requestingDeviceId = credentials.deviceId,
+                secretName = secretName,
+                requestId = createUniqueTxnId()
+        )
+
+        verifMutex.withLock {
+            outgoingSecretRequests.add(toDeviceContent)
+        }
+
+        val contentMap = MXUsersDevicesMap<Any>()
+        contentMap.setObject(cryptoDeviceInfo.userId, cryptoDeviceInfo.deviceId, toDeviceContent)
+
+        val params = SendToDeviceTask.Params(
+                eventType = EventType.REQUEST_SECRET,
+                contentMap = contentMap
+        )
+        try {
+            withContext(coroutineDispatchers.io) {
+                sendToDeviceTask.executeRetry(params, 3)
+            }
+            Timber.tag(loggerTag.value)
+                    .d("Secret request sent for $secretName to ${cryptoDeviceInfo.shortDebugString()}")
+            // TODO update the audit trail
+        } catch (failure: Throwable) {
+            Timber.tag(loggerTag.value)
+                    .w("Failed to request secret $secretName to ${cryptoDeviceInfo.shortDebugString()}")
+        }
+    }
+
+    suspend fun onSecretSendReceived(toDevice: Event, handleGossip: ((name: String, value: String) -> Boolean)) {
+        Timber.tag(loggerTag.value)
+                .i("onSecretSend() from ${toDevice.senderId} : onSecretSendReceived ${toDevice.content?.get("sender_key")}")
+        if (!toDevice.isEncrypted()) {
+            // secret send messages must be encrypted
+            Timber.tag(loggerTag.value).e("onSecretSend() :Received unencrypted secret send event")
+            return
+        }
+
+        // Was that sent by us?
+        if (toDevice.senderId != credentials.userId) {
+            Timber.tag(loggerTag.value).e("onSecretSend() : Ignore secret from other user ${toDevice.senderId}")
+            return
+        }
+
+        val secretContent = toDevice.getClearContent().toModel<SecretSendEventContent>() ?: return
+
+        val existingRequest = verifMutex.withLock {
+            outgoingSecretRequests.firstOrNull { it.requestId == secretContent.requestId }
+        }
+
+        // As per spec:
+        // Clients should ignore m.secret.send events received from devices that it did not send an m.secret.request event to.
+        if (existingRequest?.secretName == null) {
+            Timber.tag(loggerTag.value).i("onSecretSend() : Ignore secret that was not requested: ${secretContent.requestId}")
+            return
+        }
+        // we don't need to cancel the request as we only request to one device
+        // just forget about the request now
+        verifMutex.withLock {
+            outgoingSecretRequests.remove(existingRequest)
+        }
+
+        if (!handleGossip(existingRequest.secretName, secretContent.secretValue)) {
+            // TODO Ask to application layer?
+            Timber.tag(loggerTag.value).v("onSecretSend() : secret not handled by SDK")
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipRequestWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipRequestWorker.kt
deleted file mode 100644
index 3b43ad672b57e0544918e0d0b484d6aee3ebadb1..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipRequestWorker.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto
-
-import android.content.Context
-import androidx.work.WorkerParameters
-import com.squareup.moshi.JsonClass
-import org.matrix.android.sdk.api.auth.data.Credentials
-import org.matrix.android.sdk.api.failure.shouldBeRetried
-import org.matrix.android.sdk.api.session.crypto.model.GossipingToDeviceObject
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingGossipingRequestState
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingRoomKeyRequest
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyShareRequest
-import org.matrix.android.sdk.api.session.crypto.model.SecretShareRequest
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.toContent
-import org.matrix.android.sdk.internal.SessionManager
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
-import org.matrix.android.sdk.internal.crypto.tasks.createUniqueTxnId
-import org.matrix.android.sdk.internal.session.SessionComponent
-import org.matrix.android.sdk.internal.util.time.Clock
-import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
-import org.matrix.android.sdk.internal.worker.SessionWorkerParams
-import timber.log.Timber
-import javax.inject.Inject
-
-internal class SendGossipRequestWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
-        SessionSafeCoroutineWorker<SendGossipRequestWorker.Params>(context, params, sessionManager, Params::class.java) {
-
-    @JsonClass(generateAdapter = true)
-    internal data class Params(
-            override val sessionId: String,
-            val keyShareRequest: OutgoingRoomKeyRequest? = null,
-            val secretShareRequest: OutgoingSecretRequest? = null,
-            // The txnId for the sendToDevice request. Nullable for compatibility reasons, but MUST always be provided
-            // to use the same value if this worker is retried.
-            val txnId: String? = null,
-            override val lastFailureMessage: String? = null
-    ) : SessionWorkerParams
-
-    @Inject lateinit var sendToDeviceTask: SendToDeviceTask
-    @Inject lateinit var cryptoStore: IMXCryptoStore
-    @Inject lateinit var credentials: Credentials
-    @Inject lateinit var clock: Clock
-
-    override fun injectWith(injector: SessionComponent) {
-        injector.inject(this)
-    }
-
-    override suspend fun doSafeWork(params: Params): Result {
-        // params.txnId should be provided in all cases now. But Params can be deserialized by
-        // the WorkManager from data serialized in a previous version of the application, so without the txnId field.
-        // So if not present, we create a txnId
-        val txnId = params.txnId ?: createUniqueTxnId()
-        val contentMap = MXUsersDevicesMap<Any>()
-        val eventType: String
-        val requestId: String
-        when {
-            params.keyShareRequest != null    -> {
-                eventType = EventType.ROOM_KEY_REQUEST
-                requestId = params.keyShareRequest.requestId
-                val toDeviceContent = RoomKeyShareRequest(
-                        requestingDeviceId = credentials.deviceId,
-                        requestId = params.keyShareRequest.requestId,
-                        action = GossipingToDeviceObject.ACTION_SHARE_REQUEST,
-                        body = params.keyShareRequest.requestBody
-                )
-                cryptoStore.saveGossipingEvent(Event(
-                        type = eventType,
-                        content = toDeviceContent.toContent(),
-                        senderId = credentials.userId
-                ).also {
-                    it.ageLocalTs = clock.epochMillis()
-                })
-
-                params.keyShareRequest.recipients.forEach { userToDeviceMap ->
-                    userToDeviceMap.value.forEach { deviceId ->
-                        contentMap.setObject(userToDeviceMap.key, deviceId, toDeviceContent)
-                    }
-                }
-            }
-            params.secretShareRequest != null -> {
-                eventType = EventType.REQUEST_SECRET
-                requestId = params.secretShareRequest.requestId
-                val toDeviceContent = SecretShareRequest(
-                        requestingDeviceId = credentials.deviceId,
-                        requestId = params.secretShareRequest.requestId,
-                        action = GossipingToDeviceObject.ACTION_SHARE_REQUEST,
-                        secretName = params.secretShareRequest.secretName
-                )
-
-                cryptoStore.saveGossipingEvent(Event(
-                        type = eventType,
-                        content = toDeviceContent.toContent(),
-                        senderId = credentials.userId
-                ).also {
-                    it.ageLocalTs = clock.epochMillis()
-                })
-
-                params.secretShareRequest.recipients.forEach { userToDeviceMap ->
-                    userToDeviceMap.value.forEach { deviceId ->
-                        contentMap.setObject(userToDeviceMap.key, deviceId, toDeviceContent)
-                    }
-                }
-            }
-            else                              -> {
-                return buildErrorResult(params, "Unknown empty gossiping request").also {
-                    Timber.e("Unknown empty gossiping request: $params")
-                }
-            }
-        }
-        try {
-            cryptoStore.updateOutgoingGossipingRequestState(requestId, OutgoingGossipingRequestState.SENDING)
-            sendToDeviceTask.execute(
-                    SendToDeviceTask.Params(
-                            eventType = eventType,
-                            contentMap = contentMap,
-                            transactionId = txnId
-                    )
-            )
-            cryptoStore.updateOutgoingGossipingRequestState(requestId, OutgoingGossipingRequestState.SENT)
-            return Result.success()
-        } catch (throwable: Throwable) {
-            return if (throwable.shouldBeRetried()) {
-                Result.retry()
-            } else {
-                cryptoStore.updateOutgoingGossipingRequestState(requestId, OutgoingGossipingRequestState.FAILED_TO_SEND)
-                buildErrorResult(params, throwable.localizedMessage ?: "error")
-            }
-        }
-    }
-
-    override fun buildErrorParams(params: Params, message: String): Params {
-        return params.copy(lastFailureMessage = params.lastFailureMessage ?: message)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipWorker.kt
deleted file mode 100644
index 113d71d387d40f643a46253273c6937393f8517b..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipWorker.kt
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto
-
-import android.content.Context
-import androidx.work.WorkerParameters
-import com.squareup.moshi.JsonClass
-import org.matrix.android.sdk.api.auth.data.Credentials
-import org.matrix.android.sdk.api.failure.shouldBeRetried
-import org.matrix.android.sdk.api.session.crypto.model.GossipingRequestState
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.content.SecretSendEventContent
-import org.matrix.android.sdk.api.session.events.model.toContent
-import org.matrix.android.sdk.internal.SessionManager
-import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
-import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
-import org.matrix.android.sdk.internal.crypto.tasks.createUniqueTxnId
-import org.matrix.android.sdk.internal.session.SessionComponent
-import org.matrix.android.sdk.internal.util.time.Clock
-import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
-import org.matrix.android.sdk.internal.worker.SessionWorkerParams
-import timber.log.Timber
-import javax.inject.Inject
-
-internal class SendGossipWorker(
-        context: Context,
-        params: WorkerParameters,
-        sessionManager: SessionManager
-) : SessionSafeCoroutineWorker<SendGossipWorker.Params>(context, params, sessionManager, Params::class.java) {
-
-    @JsonClass(generateAdapter = true)
-    internal data class Params(
-            override val sessionId: String,
-            val secretValue: String,
-            val requestUserId: String?,
-            val requestDeviceId: String?,
-            val requestId: String?,
-            // The txnId for the sendToDevice request. Nullable for compatibility reasons, but MUST always be provided
-            // to use the same value if this worker is retried.
-            val txnId: String? = null,
-            override val lastFailureMessage: String? = null
-    ) : SessionWorkerParams
-
-    @Inject lateinit var sendToDeviceTask: SendToDeviceTask
-    @Inject lateinit var cryptoStore: IMXCryptoStore
-    @Inject lateinit var credentials: Credentials
-    @Inject lateinit var messageEncrypter: MessageEncrypter
-    @Inject lateinit var ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction
-    @Inject lateinit var clock: Clock
-
-    override fun injectWith(injector: SessionComponent) {
-        injector.inject(this)
-    }
-
-    override suspend fun doSafeWork(params: Params): Result {
-        // params.txnId should be provided in all cases now. But Params can be deserialized by
-        // the WorkManager from data serialized in a previous version of the application, so without the txnId field.
-        // So if not present, we create a txnId
-        val txnId = params.txnId ?: createUniqueTxnId()
-        val eventType: String = EventType.SEND_SECRET
-
-        val toDeviceContent = SecretSendEventContent(
-                requestId = params.requestId ?: "",
-                secretValue = params.secretValue
-        )
-
-        val requestingUserId = params.requestUserId ?: ""
-        val requestingDeviceId = params.requestDeviceId ?: ""
-        val deviceInfo = cryptoStore.getUserDevice(requestingUserId, requestingDeviceId)
-                ?: return buildErrorResult(params, "Unknown deviceInfo, cannot send message").also {
-                    cryptoStore.updateGossipingRequestState(
-                            requestUserId = params.requestUserId,
-                            requestDeviceId = params.requestDeviceId,
-                            requestId = params.requestId,
-                            state = GossipingRequestState.FAILED_TO_ACCEPTED
-                    )
-                    Timber.e("Unknown deviceInfo, cannot send message, sessionId: ${params.requestDeviceId}")
-                }
-
-        val sendToDeviceMap = MXUsersDevicesMap<Any>()
-
-        val devicesByUser = mapOf(requestingUserId to listOf(deviceInfo))
-        val usersDeviceMap = ensureOlmSessionsForDevicesAction.handle(devicesByUser)
-        val olmSessionResult = usersDeviceMap.getObject(requestingUserId, requestingDeviceId)
-        if (olmSessionResult?.sessionId == null) {
-            // no session with this device, probably because there
-            // were no one-time keys.
-            return buildErrorResult(params, "no session with this device").also {
-                cryptoStore.updateGossipingRequestState(
-                        requestUserId = params.requestUserId,
-                        requestDeviceId = params.requestDeviceId,
-                        requestId = params.requestId,
-                        state = GossipingRequestState.FAILED_TO_ACCEPTED
-                )
-                Timber.e("no session with this device $requestingDeviceId, probably because there were no one-time keys.")
-            }
-        }
-
-        val payloadJson = mapOf(
-                "type" to EventType.SEND_SECRET,
-                "content" to toDeviceContent.toContent()
-        )
-
-        try {
-            val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
-            sendToDeviceMap.setObject(requestingUserId, requestingDeviceId, encodedPayload)
-        } catch (failure: Throwable) {
-            Timber.e("## Fail to encrypt gossip + ${failure.localizedMessage}")
-        }
-
-        cryptoStore.saveGossipingEvent(Event(
-                type = eventType,
-                content = toDeviceContent.toContent(),
-                senderId = credentials.userId
-        ).also {
-            it.ageLocalTs = clock.epochMillis()
-        })
-
-        try {
-            sendToDeviceTask.execute(
-                    SendToDeviceTask.Params(
-                            eventType = EventType.ENCRYPTED,
-                            contentMap = sendToDeviceMap,
-                            transactionId = txnId
-                    )
-            )
-            cryptoStore.updateGossipingRequestState(
-                    requestUserId = params.requestUserId,
-                    requestDeviceId = params.requestDeviceId,
-                    requestId = params.requestId,
-                    state = GossipingRequestState.ACCEPTED
-            )
-            return Result.success()
-        } catch (throwable: Throwable) {
-            return if (throwable.shouldBeRetried()) {
-                Result.retry()
-            } else {
-                cryptoStore.updateGossipingRequestState(
-                        requestUserId = params.requestUserId,
-                        requestDeviceId = params.requestDeviceId,
-                        requestId = params.requestId,
-                        state = GossipingRequestState.FAILED_TO_ACCEPTED
-                )
-                buildErrorResult(params, throwable.localizedMessage ?: "error")
-            }
-        }
-    }
-
-    override fun buildErrorParams(params: Params, message: String): Params {
-        return params.copy(lastFailureMessage = params.lastFailureMessage ?: message)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt
index fffc2b4d4bbd05e01432cb54a888ef29d9e1f10d..c728f1b6827a427dda5124d3398b9615b0b5bce2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt
@@ -45,7 +45,7 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(
 
     /**
      * We want to synchronize a bit here, because we are iterating to check existing olm session and
-     * also adding some
+     * also adding some.
      */
     suspend fun handle(devicesByUser: Map<String, List<CryptoDeviceInfo>>, force: Boolean = false): MXUsersDevicesMap<MXOlmSessionResult> {
         ensureMutex.withLock {
@@ -137,10 +137,14 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(
                 olmDevice.verifySignature(fingerprint, oneTimeKey.signalableJSONDictionary(), signature)
                 isVerified = true
             } catch (e: Exception) {
-                Timber.tag(loggerTag.value).d(e, "verifyKeyAndStartSession() : Verify error for otk: ${oneTimeKey.signalableJSONDictionary()}," +
-                        " signature:$signature fingerprint:$fingerprint")
-                Timber.tag(loggerTag.value).e("verifyKeyAndStartSession() : Verify error for ${deviceInfo.userId}|${deviceInfo.deviceId} " +
-                        " - signable json ${oneTimeKey.signalableJSONDictionary()}")
+                Timber.tag(loggerTag.value).d(
+                        e, "verifyKeyAndStartSession() : Verify error for otk: ${oneTimeKey.signalableJSONDictionary()}," +
+                        " signature:$signature fingerprint:$fingerprint"
+                )
+                Timber.tag(loggerTag.value).e(
+                        "verifyKeyAndStartSession() : Verify error for ${deviceInfo.userId}|${deviceInfo.deviceId} " +
+                                " - signable json ${oneTimeKey.signalableJSONDictionary()}"
+                )
                 errorMessage = e.message
             }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt
index 86674b4ac55046bfd9499388e6c0a47973a93f82..22c4e59b1899dd3f23e74cf17ad2019f0df034e7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt
@@ -17,12 +17,13 @@
 package org.matrix.android.sdk.internal.crypto.actions
 
 import androidx.annotation.WorkerThread
+import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.listeners.ProgressListener
+import org.matrix.android.sdk.api.logger.LoggerTag
 import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
 import org.matrix.android.sdk.internal.crypto.MXOlmDevice
 import org.matrix.android.sdk.internal.crypto.MegolmSessionData
-import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager
+import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
 import org.matrix.android.sdk.internal.crypto.RoomDecryptorProvider
 import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXMegolmDecryption
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
@@ -30,12 +31,13 @@ import org.matrix.android.sdk.internal.util.time.Clock
 import timber.log.Timber
 import javax.inject.Inject
 
-internal class MegolmSessionDataImporter @Inject constructor(
-        private val olmDevice: MXOlmDevice,
-        private val roomDecryptorProvider: RoomDecryptorProvider,
-        private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
-        private val cryptoStore: IMXCryptoStore,
-        private val clock: Clock,
+private val loggerTag = LoggerTag("MegolmSessionDataImporter", LoggerTag.CRYPTO)
+
+internal class MegolmSessionDataImporter @Inject constructor(private val olmDevice: MXOlmDevice,
+                                                             private val roomDecryptorProvider: RoomDecryptorProvider,
+                                                             private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
+                                                             private val cryptoStore: IMXCryptoStore,
+                                                             private val clock: Clock,
 ) {
 
     /**
@@ -66,19 +68,23 @@ internal class MegolmSessionDataImporter @Inject constructor(
             if (null != decrypting) {
                 try {
                     val sessionId = megolmSessionData.sessionId
-                    Timber.v("## importRoomKeys retrieve senderKey " + megolmSessionData.senderKey + " sessionId " + sessionId)
+                    Timber.tag(loggerTag.value).v("## importRoomKeys retrieve senderKey ${megolmSessionData.senderKey} sessionId $sessionId")
 
                     totalNumbersOfImportedKeys++
 
                     // cancel any outstanding room key requests for this session
-                    val roomKeyRequestBody = RoomKeyRequestBody(
-                            algorithm = megolmSessionData.algorithm,
-                            roomId = megolmSessionData.roomId,
-                            senderKey = megolmSessionData.senderKey,
-                            sessionId = megolmSessionData.sessionId
-                    )
 
-                    outgoingGossipingRequestManager.cancelRoomKeyRequest(roomKeyRequestBody)
+                    Timber.tag(loggerTag.value).d("Imported megolm session $sessionId from backup=$fromBackup in ${megolmSessionData.roomId}")
+                    outgoingKeyRequestManager.postCancelRequestForSessionIfNeeded(
+                            megolmSessionData.sessionId ?: "",
+                            megolmSessionData.roomId ?: "",
+                            megolmSessionData.senderKey ?: "",
+                            tryOrNull {
+                                olmInboundGroupSessionWrappers
+                                        .firstOrNull { it.olmInboundGroupSession?.sessionIdentifier() == megolmSessionData.sessionId }
+                                        ?.firstKnownIndex?.toInt()
+                            } ?: 0
+                    )
 
                     // Have another go at decrypting events sent with this session
                     when (decrypting) {
@@ -87,7 +93,7 @@ internal class MegolmSessionDataImporter @Inject constructor(
                         }
                     }
                 } catch (e: Exception) {
-                    Timber.e(e, "## importRoomKeys() : onNewSession failed")
+                    Timber.tag(loggerTag.value).e(e, "## importRoomKeys() : onNewSession failed")
                 }
             }
 
@@ -109,7 +115,7 @@ internal class MegolmSessionDataImporter @Inject constructor(
 
         val t1 = clock.epochMillis()
 
-        Timber.v("## importMegolmSessionsData : sessions import " + (t1 - t0) + " ms (" + megolmSessionsData.size + " sessions)")
+        Timber.tag(loggerTag.value).v("## importMegolmSessionsData : sessions import " + (t1 - t0) + " ms (" + megolmSessionsData.size + " sessions)")
 
         return ImportRoomKeysResult(totalNumbersOfKeys, totalNumbersOfImportedKeys)
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt
index 2ea4e1dd29f5ddec3466990554233c345f4d0bcb..34006ecfde5910ff4b5684a4ec769ef0609a41e5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt
@@ -17,19 +17,17 @@
 package org.matrix.android.sdk.internal.crypto.algorithms
 
 import org.matrix.android.sdk.api.session.crypto.MXCryptoError
-import org.matrix.android.sdk.api.session.crypto.model.IncomingRoomKeyRequest
-import org.matrix.android.sdk.api.session.crypto.model.IncomingSecretShareRequest
 import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.internal.crypto.keysbackup.DefaultKeysBackupService
 
 /**
- * An interface for decrypting data
+ * An interface for decrypting data.
  */
 internal interface IMXDecrypting {
 
     /**
-     * Decrypt an event
+     * Decrypt an event.
      *
      * @param event    the raw event.
      * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
@@ -44,23 +42,4 @@ internal interface IMXDecrypting {
      * @param event the key event.
      */
     fun onRoomKeyEvent(event: Event, defaultKeysBackupService: DefaultKeysBackupService) {}
-
-    /**
-     * Determine if we have the keys necessary to respond to a room key request
-     *
-     * @param request keyRequest
-     * @return true if we have the keys and could (theoretically) share
-     */
-    fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean = false
-
-    /**
-     * Send the response to a room key request.
-     *
-     * @param request keyRequest
-     */
-    fun shareKeysWithDevice(request: IncomingRoomKeyRequest) {}
-
-    fun shareSecretWithDevice(request: IncomingSecretShareRequest, secretValue: String) {}
-
-    fun requestKeysForEvent(event: Event, withHeld: Boolean)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt
index 5294429198a81868ee0914bc824466afe89321a4..1d8412020876990c6631da60b05743409f676f4d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.crypto.algorithms
 import org.matrix.android.sdk.api.session.events.model.Content
 
 /**
- * An interface for encrypting data
+ * An interface for encrypting data.
  */
 internal interface IMXEncrypting {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXWithHeldExtension.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXWithHeldExtension.kt
deleted file mode 100644
index 585bcdbbdef98f5f542ef0af5156eceaacad2d27..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXWithHeldExtension.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto.algorithms
-
-import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
-
-internal interface IMXWithHeldExtension {
-    fun onRoomKeyWithHeldEvent(withHeldInfo: RoomKeyWithHeldContent)
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt
index 4c407c9eb967a8e251ad065ac108eb4d569f0630..8321b73b758c2baa34dc780cddf5bbc22199b1cb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt
@@ -17,51 +17,32 @@
 package org.matrix.android.sdk.internal.crypto.algorithms.megolm
 
 import dagger.Lazy
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.sync.withLock
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
 import org.matrix.android.sdk.api.logger.LoggerTag
 import org.matrix.android.sdk.api.session.crypto.MXCryptoError
 import org.matrix.android.sdk.api.session.crypto.NewSessionListener
 import org.matrix.android.sdk.api.session.crypto.model.ForwardedRoomKeyContent
-import org.matrix.android.sdk.api.session.crypto.model.IncomingRoomKeyRequest
 import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
 import org.matrix.android.sdk.api.session.events.model.content.RoomKeyContent
-import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
 import org.matrix.android.sdk.api.session.events.model.toModel
-import org.matrix.android.sdk.internal.crypto.DeviceListManager
 import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager
-import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
-import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
+import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
 import org.matrix.android.sdk.internal.crypto.algorithms.IMXDecrypting
-import org.matrix.android.sdk.internal.crypto.algorithms.IMXWithHeldExtension
 import org.matrix.android.sdk.internal.crypto.keysbackup.DefaultKeysBackupService
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
 import org.matrix.android.sdk.internal.session.StreamEventsManager
 import timber.log.Timber
 
 private val loggerTag = LoggerTag("MXMegolmDecryption", LoggerTag.CRYPTO)
 
-internal class MXMegolmDecryption(private val userId: String,
-                                  private val olmDevice: MXOlmDevice,
-                                  private val deviceListManager: DeviceListManager,
-                                  private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
-                                  private val messageEncrypter: MessageEncrypter,
-                                  private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
-                                  private val cryptoStore: IMXCryptoStore,
-                                  private val sendToDeviceTask: SendToDeviceTask,
-                                  private val coroutineDispatchers: MatrixCoroutineDispatchers,
-                                  private val cryptoCoroutineScope: CoroutineScope,
-                                  private val liveEventManager: Lazy<StreamEventsManager>
-) : IMXDecrypting, IMXWithHeldExtension {
+internal class MXMegolmDecryption(
+        private val olmDevice: MXOlmDevice,
+        private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
+        private val cryptoStore: IMXCryptoStore,
+        private val liveEventManager: Lazy<StreamEventsManager>
+) : IMXDecrypting {
 
     var newSessionListener: NewSessionListener? = null
 
@@ -73,10 +54,7 @@ internal class MXMegolmDecryption(private val userId: String,
 
     @Throws(MXCryptoError::class)
     override suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
-        // If cross signing is enabled, we don't send request until the keys are trusted
-        // There could be a race effect here when xsigning is enabled, we should ensure that keys was downloaded once
-        val requestOnFail = cryptoStore.getMyCrossSigningInfo()?.isTrusted() == true
-        return decryptEvent(event, timeline, requestOnFail)
+        return decryptEvent(event, timeline, true)
     }
 
     @Throws(MXCryptoError::class)
@@ -96,11 +74,13 @@ internal class MXMegolmDecryption(private val userId: String,
         }
 
         return runCatching {
-            olmDevice.decryptGroupMessage(encryptedEventContent.ciphertext,
+            olmDevice.decryptGroupMessage(
+                    encryptedEventContent.ciphertext,
                     event.roomId,
                     timeline,
                     encryptedEventContent.sessionId,
-                    encryptedEventContent.senderKey)
+                    encryptedEventContent.senderKey
+            )
         }
                 .fold(
                         { olmDecryptionResult ->
@@ -124,27 +104,27 @@ internal class MXMegolmDecryption(private val userId: String,
                             if (throwable is MXCryptoError.OlmError) {
                                 // TODO Check the value of .message
                                 if (throwable.olmException.message == "UNKNOWN_MESSAGE_INDEX") {
-                                    // addEventToPendingList(event, timeline)
-                                    // The session might has been partially withheld (and only pass ratcheted)
+                                    // So we know that session, but it's ratcheted and we can't decrypt at that index
+
+                                    if (requestKeysOnFail) {
+                                        requestKeysForEvent(event)
+                                    }
+                                    // Check if partially withheld
                                     val withHeldInfo = cryptoStore.getWithHeldMegolmSession(event.roomId, encryptedEventContent.sessionId)
                                     if (withHeldInfo != null) {
-                                        if (requestKeysOnFail) {
-                                            requestKeysForEvent(event, true)
-                                        }
                                         // Encapsulate as withHeld exception
-                                        throw MXCryptoError.Base(MXCryptoError.ErrorType.KEYS_WITHHELD,
+                                        throw MXCryptoError.Base(
+                                                MXCryptoError.ErrorType.KEYS_WITHHELD,
                                                 withHeldInfo.code?.value ?: "",
-                                                withHeldInfo.reason)
-                                    }
-
-                                    if (requestKeysOnFail) {
-                                        requestKeysForEvent(event, false)
+                                                withHeldInfo.reason
+                                        )
                                     }
 
                                     throw MXCryptoError.Base(
                                             MXCryptoError.ErrorType.UNKNOWN_MESSAGE_INDEX,
                                             "UNKNOWN_MESSAGE_INDEX",
-                                            null)
+                                            null
+                                    )
                                 }
 
                                 val reason = String.format(MXCryptoError.OLM_REASON, throwable.olmException.message)
@@ -153,28 +133,26 @@ internal class MXMegolmDecryption(private val userId: String,
                                 throw MXCryptoError.Base(
                                         MXCryptoError.ErrorType.OLM,
                                         reason,
-                                        detailedReason)
+                                        detailedReason
+                                )
                             }
                             if (throwable is MXCryptoError.Base) {
-                                if (
-                                /** if the session is unknown*/
-                                        throwable.errorType == MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID
-                                ) {
+                                if (throwable.errorType == MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID) {
+                                    // Check if it was withheld by sender to enrich error code
                                     val withHeldInfo = cryptoStore.getWithHeldMegolmSession(event.roomId, encryptedEventContent.sessionId)
                                     if (withHeldInfo != null) {
                                         if (requestKeysOnFail) {
-                                            requestKeysForEvent(event, true)
+                                            requestKeysForEvent(event)
                                         }
                                         // Encapsulate as withHeld exception
-                                        throw MXCryptoError.Base(MXCryptoError.ErrorType.KEYS_WITHHELD,
+                                        throw MXCryptoError.Base(
+                                                MXCryptoError.ErrorType.KEYS_WITHHELD,
                                                 withHeldInfo.code?.value ?: "",
                                                 withHeldInfo.reason)
-                                    } else {
-                                        // This is un-used in Matrix Android SDK2, not sure if needed
-                                        // addEventToPendingList(event, timeline)
-                                        if (requestKeysOnFail) {
-                                            requestKeysForEvent(event, false)
-                                        }
+                                    }
+
+                                    if (requestKeysOnFail) {
+                                        requestKeysForEvent(event)
                                     }
                                 }
                             }
@@ -190,55 +168,10 @@ internal class MXMegolmDecryption(private val userId: String,
      *
      * @param event the event
      */
-    override fun requestKeysForEvent(event: Event, withHeld: Boolean) {
-        val sender = event.senderId ?: return
-        val encryptedEventContent = event.content.toModel<EncryptedEventContent>()
-        val senderDevice = encryptedEventContent?.deviceId ?: return
-
-        val recipients = if (event.senderId == userId || withHeld) {
-            mapOf(
-                    userId to listOf("*")
-            )
-        } else {
-            // for the case where you share the key with a device that has a broken olm session
-            // The other user might Re-shares a megolm session key with devices if the key has already been
-            // sent to them.
-            mapOf(
-                    userId to listOf("*"),
-                    sender to listOf(senderDevice)
-            )
-        }
-
-        val requestBody = RoomKeyRequestBody(
-                roomId = event.roomId,
-                algorithm = encryptedEventContent.algorithm,
-                senderKey = encryptedEventContent.senderKey,
-                sessionId = encryptedEventContent.sessionId
-        )
-
-        outgoingGossipingRequestManager.sendRoomKeyRequest(requestBody, recipients)
+    private fun requestKeysForEvent(event: Event) {
+        outgoingKeyRequestManager.requestKeyForEvent(event, false)
     }
 
-//    /**
-//     * Add an event to the list of those we couldn't decrypt the first time we
-//     * saw them.
-//     *
-//     * @param event      the event to try to decrypt later
-//     * @param timelineId the timeline identifier
-//     */
-//    private fun addEventToPendingList(event: Event, timelineId: String) {
-//        val encryptedEventContent = event.content.toModel<EncryptedEventContent>() ?: return
-//        val pendingEventsKey = "${encryptedEventContent.senderKey}|${encryptedEventContent.sessionId}"
-//
-//        val timeline = pendingEvents.getOrPut(pendingEventsKey) { HashMap() }
-//        val events = timeline.getOrPut(timelineId) { ArrayList() }
-//
-//        if (event !in events) {
-//            Timber.v("## CRYPTO | addEventToPendingList() : add Event ${event.eventId} in room id ${event.roomId}")
-//            events.add(event)
-//        }
-//    }
-
     /**
      * Handle a key event.
      *
@@ -258,6 +191,11 @@ internal class MXMegolmDecryption(private val userId: String,
             return
         }
         if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
+            if (!cryptoStore.isKeyGossipingEnabled()) {
+                Timber.tag(loggerTag.value)
+                        .i("onRoomKeyEvent(), ignore forward adding as per crypto config : ${roomKeyContent.roomId}|${roomKeyContent.sessionId}")
+                return
+            }
             Timber.tag(loggerTag.value).i("onRoomKeyEvent(), forward adding key : ${roomKeyContent.roomId}|${roomKeyContent.sessionId}")
             val forwardedRoomKeyContent = event.getClearContent().toModel<ForwardedRoomKeyContent>()
                     ?: return
@@ -298,32 +236,63 @@ internal class MXMegolmDecryption(private val userId: String,
         }
 
         Timber.tag(loggerTag.value).i("onRoomKeyEvent addInboundGroupSession ${roomKeyContent.sessionId}")
-        val added = olmDevice.addInboundGroupSession(roomKeyContent.sessionId,
+        val addSessionResult = olmDevice.addInboundGroupSession(
+                roomKeyContent.sessionId,
                 roomKeyContent.sessionKey,
                 roomKeyContent.roomId,
                 senderKey,
                 forwardingCurve25519KeyChain,
                 keysClaimed,
-                exportFormat)
-
-        if (added) {
-            defaultKeysBackupService.maybeBackupKeys()
+                exportFormat
+        )
 
-            val content = RoomKeyRequestBody(
-                    algorithm = roomKeyContent.algorithm,
-                    roomId = roomKeyContent.roomId,
-                    sessionId = roomKeyContent.sessionId,
-                    senderKey = senderKey
-            )
+        when (addSessionResult) {
+            is MXOlmDevice.AddSessionResult.Imported               -> addSessionResult.ratchetIndex
+            is MXOlmDevice.AddSessionResult.NotImportedHigherIndex -> addSessionResult.newIndex
+            else                                                   -> null
+        }?.let { index ->
+            if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
+                val fromDevice = (event.content?.get("sender_key") as? String)?.let { senderDeviceIdentityKey ->
+                    cryptoStore.getUserDeviceList(event.senderId ?: "")
+                            ?.firstOrNull {
+                                it.identityKey() == senderDeviceIdentityKey
+                            }
+                }?.deviceId
+
+                outgoingKeyRequestManager.onRoomKeyForwarded(
+                        sessionId = roomKeyContent.sessionId,
+                        algorithm = roomKeyContent.algorithm ?: "",
+                        roomId = roomKeyContent.roomId,
+                        senderKey = senderKey,
+                        fromIndex = index,
+                        fromDevice = fromDevice,
+                        event = event)
+
+                cryptoStore.saveIncomingForwardKeyAuditTrail(
+                        roomId = roomKeyContent.roomId,
+                        sessionId = roomKeyContent.sessionId,
+                        senderKey = senderKey,
+                        algorithm = roomKeyContent.algorithm ?: "",
+                        userId = event.senderId ?: "",
+                        deviceId = fromDevice ?: "",
+                        chainIndex = index.toLong())
+
+                // The index is used to decide if we cancel sent request or if we wait for a better key
+                outgoingKeyRequestManager.postCancelRequestForSessionIfNeeded(roomKeyContent.sessionId, roomKeyContent.roomId, senderKey, index)
+            }
+        }
 
-            outgoingGossipingRequestManager.cancelRoomKeyRequest(content)
+        if (addSessionResult is MXOlmDevice.AddSessionResult.Imported) {
+            Timber.tag(loggerTag.value)
+                    .d("onRoomKeyEvent(${event.getClearType()}) : Added megolm session ${roomKeyContent.sessionId} in ${roomKeyContent.roomId}")
+            defaultKeysBackupService.maybeBackupKeys()
 
             onNewSession(roomKeyContent.roomId, senderKey, roomKeyContent.sessionId)
         }
     }
 
     /**
-     * Check if the some messages can be decrypted with a new session
+     * Check if the some messages can be decrypted with a new session.
      *
      * @param roomId the room id where the new Megolm session has been created for, may be null when importing from external sessions
      * @param senderKey the session sender key
@@ -333,77 +302,4 @@ internal class MXMegolmDecryption(private val userId: String,
         Timber.tag(loggerTag.value).v("ON NEW SESSION $sessionId - $senderKey")
         newSessionListener?.onNewSession(roomId, senderKey, sessionId)
     }
-
-    override fun hasKeysForKeyRequest(request: IncomingRoomKeyRequest): Boolean {
-        val roomId = request.requestBody?.roomId ?: return false
-        val senderKey = request.requestBody.senderKey ?: return false
-        val sessionId = request.requestBody.sessionId ?: return false
-        return olmDevice.hasInboundSessionKeys(roomId, senderKey, sessionId)
-    }
-
-    override fun shareKeysWithDevice(request: IncomingRoomKeyRequest) {
-        // sanity checks
-        if (request.requestBody == null) {
-            return
-        }
-        val userId = request.userId ?: return
-
-        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
-            val body = request.requestBody
-            val sessionHolder = try {
-                olmDevice.getInboundGroupSession(body.sessionId, body.senderKey, body.roomId)
-            } catch (failure: Throwable) {
-                Timber.tag(loggerTag.value).e(failure, "shareKeysWithDevice: failed to get session for request $body")
-                return@launch
-            }
-
-            val export = sessionHolder.mutex.withLock {
-                sessionHolder.wrapper.exportKeys()
-            } ?: return@launch Unit.also {
-                Timber.tag(loggerTag.value).e("shareKeysWithDevice: failed to export group session ${body.sessionId}")
-            }
-
-            runCatching { deviceListManager.downloadKeys(listOf(userId), false) }
-                    .mapCatching {
-                        val deviceId = request.deviceId
-                        val deviceInfo = cryptoStore.getUserDevice(userId, deviceId ?: "")
-                        if (deviceInfo == null) {
-                            throw RuntimeException()
-                        } else {
-                            val devicesByUser = mapOf(userId to listOf(deviceInfo))
-                            val usersDeviceMap = ensureOlmSessionsForDevicesAction.handle(devicesByUser)
-                            val olmSessionResult = usersDeviceMap.getObject(userId, deviceId)
-                            if (olmSessionResult?.sessionId == null) {
-                                // no session with this device, probably because there
-                                // were no one-time keys.
-                                Timber.tag(loggerTag.value).e("no session with this device $deviceId, probably because there were no one-time keys.")
-                                return@mapCatching
-                            }
-                            Timber.tag(loggerTag.value).i("shareKeysWithDevice() : sharing session ${body.sessionId} with device $userId:$deviceId")
-
-                            val payloadJson = mapOf(
-                                    "type" to EventType.FORWARDED_ROOM_KEY,
-                                    "content" to export
-                            )
-
-                            val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
-                            val sendToDeviceMap = MXUsersDevicesMap<Any>()
-                            sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
-                            Timber.tag(loggerTag.value).i("shareKeysWithDevice() : sending ${body.sessionId} to $userId:$deviceId")
-                            val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
-                            try {
-                                sendToDeviceTask.execute(sendToDeviceParams)
-                            } catch (failure: Throwable) {
-                                Timber.tag(loggerTag.value).e(failure, "shareKeysWithDevice() : Failed to send ${body.sessionId} to $userId:$deviceId")
-                            }
-                        }
-                    }
-        }
-    }
-
-    override fun onRoomKeyWithHeldEvent(withHeldInfo: RoomKeyWithHeldContent) {
-        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
-            cryptoStore.addWithHeldMegolmSession(withHeldInfo)
-        }
-    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt
index 3eba04b9f1840e55bc743d1de7fd7e146037c00e..096773a9594772d050829bf9cf7a62a9d073d844 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt
@@ -17,45 +17,24 @@
 package org.matrix.android.sdk.internal.crypto.algorithms.megolm
 
 import dagger.Lazy
-import kotlinx.coroutines.CoroutineScope
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.internal.crypto.DeviceListManager
 import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager
-import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
-import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
+import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
-import org.matrix.android.sdk.internal.di.UserId
 import org.matrix.android.sdk.internal.session.StreamEventsManager
 import javax.inject.Inject
 
 internal class MXMegolmDecryptionFactory @Inject constructor(
-        @UserId private val userId: String,
         private val olmDevice: MXOlmDevice,
-        private val deviceListManager: DeviceListManager,
-        private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
-        private val messageEncrypter: MessageEncrypter,
-        private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
+        private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
         private val cryptoStore: IMXCryptoStore,
-        private val sendToDeviceTask: SendToDeviceTask,
-        private val coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val cryptoCoroutineScope: CoroutineScope,
         private val eventsManager: Lazy<StreamEventsManager>
 ) {
 
     fun create(): MXMegolmDecryption {
         return MXMegolmDecryption(
-                userId,
                 olmDevice,
-                deviceListManager,
-                outgoingGossipingRequestManager,
-                messageEncrypter,
-                ensureOlmSessionsForDevicesAction,
+                outgoingKeyRequestManager,
                 cryptoStore,
-                sendToDeviceTask,
-                coroutineDispatchers,
-                cryptoCoroutineScope,
                 eventsManager)
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt
index b31b5e8a645e055e264fae305769db3535101cc8..79e907945fc9e403590f2377097aad29857e700d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt
@@ -28,7 +28,6 @@ import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
 import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
 import org.matrix.android.sdk.api.session.crypto.model.forEach
 import org.matrix.android.sdk.api.session.events.model.Content
-import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
 import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
@@ -80,7 +79,7 @@ internal class MXMegolmEncryption(
     }
 
     // Default rotation periods
-    // TODO: Make it configurable via parameters
+    // TODO Make it configurable via parameters
     // Session rotation periods
     private var sessionRotationPeriodMsgs: Int = 100
     private var sessionRotationPeriodMs: Int = 7 * 24 * 3600 * 1000
@@ -161,7 +160,7 @@ internal class MXMegolmEncryption(
     }
 
     /**
-     * Ensure the outbound session
+     * Ensure the outbound session.
      *
      * @param devicesInRoom the devices list
      */
@@ -197,7 +196,7 @@ internal class MXMegolmEncryption(
     }
 
     /**
-     * Share the device key to a list of users
+     * Share the device key to a list of users.
      *
      * @param session        the session info
      * @param devicesByUsers the devices map
@@ -226,7 +225,7 @@ internal class MXMegolmEncryption(
     }
 
     /**
-     * Share the device keys of a an user
+     * Share the device keys of a an user.
      *
      * @param session       the session info
      * @param devicesByUser the devices map
@@ -285,25 +284,14 @@ internal class MXMegolmEncryption(
         // attempted to share with) rather than the contentMap (those we did
         // share with), because we don't want to try to claim a one-time-key
         // for dead devices on every message.
-        val gossipingEventBuffer = arrayListOf<Event>()
-        for ((userId, devicesToShareWith) in devicesByUser) {
+        for ((_, devicesToShareWith) in devicesByUser) {
             for (deviceInfo in devicesToShareWith) {
                 session.sharedWithHelper.markedSessionAsShared(deviceInfo, chainIndex)
-                gossipingEventBuffer.add(
-                        Event(
-                                type = EventType.ROOM_KEY,
-                                senderId = myUserId,
-                                content = submap.apply {
-                                    this["session_key"] = ""
-                                    // we add a fake key for trail
-                                    this["_dest"] = "$userId|${deviceInfo.deviceId}"
-                                }
-                        ))
+                // XXX is it needed to add it to the audit trail?
+                // For now decided that no, we are more interested by forward trail
             }
         }
 
-        cryptoStore.saveGossipingEvents(gossipingEventBuffer)
-
         if (haveTargets) {
             t0 = clock.epochMillis()
             Timber.tag(loggerTag.value).i("shareUserDevicesKey() ${session.sessionId} : has target")
@@ -337,15 +325,17 @@ internal class MXMegolmEncryption(
                                           sessionId: String,
                                           senderKey: String?,
                                           code: WithHeldCode) {
-        Timber.tag(loggerTag.value).d("notifyKeyWithHeld() :sending withheld for session:$sessionId and code $code to" +
-                " ${targets.joinToString { "${it.userId}|${it.deviceId}" }}"
+        Timber.tag(loggerTag.value).d(
+                "notifyKeyWithHeld() :sending withheld for session:$sessionId and code $code to" +
+                        " ${targets.joinToString { "${it.userId}|${it.deviceId}" }}"
         )
         val withHeldContent = RoomKeyWithHeldContent(
                 roomId = roomId,
                 senderKey = senderKey,
                 algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
                 sessionId = sessionId,
-                codeString = code.value
+                codeString = code.value,
+                fromDevice = myDeviceId
         )
         val params = SendToDeviceTask.Params(
                 EventType.ROOM_KEY_WITHHELD,
@@ -366,7 +356,7 @@ internal class MXMegolmEncryption(
     }
 
     /**
-     * process the pending encryptions
+     * process the pending encryptions.
      */
     private fun encryptContent(session: MXOutboundSessionInfo, eventType: String, eventContent: Content): Content {
         // Everything is in place, encrypt all pending events
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt
index 59d78c3e05c8036a98b33720c24c14dd88868258..61ad345c62ca1b62d3ac399f19ea8d59849b7187 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt
@@ -36,6 +36,7 @@ internal class SharedWithHelper(
                 userId = deviceInfo.userId,
                 deviceId = deviceInfo.deviceId,
                 deviceIdentityKey = deviceInfo.identityKey() ?: "",
-                chainIndex = chainIndex)
+                chainIndex = chainIndex
+        )
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt
index 0db8700852fba67366db25d80614c5346d2e397c..1e66fe84c96b51135a72e267ae18e0f271468af5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt
@@ -45,20 +45,26 @@ internal class MXOlmDecryption(
     override suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
         val olmEventContent = event.content.toModel<OlmEventContent>() ?: run {
             Timber.tag(loggerTag.value).e("## decryptEvent() : bad event format")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_EVENT_FORMAT,
-                    MXCryptoError.BAD_EVENT_FORMAT_TEXT_REASON)
+            throw MXCryptoError.Base(
+                    MXCryptoError.ErrorType.BAD_EVENT_FORMAT,
+                    MXCryptoError.BAD_EVENT_FORMAT_TEXT_REASON
+            )
         }
 
         val cipherText = olmEventContent.ciphertext ?: run {
             Timber.tag(loggerTag.value).e("## decryptEvent() : missing cipher text")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_CIPHER_TEXT,
-                    MXCryptoError.MISSING_CIPHER_TEXT_REASON)
+            throw MXCryptoError.Base(
+                    MXCryptoError.ErrorType.MISSING_CIPHER_TEXT,
+                    MXCryptoError.MISSING_CIPHER_TEXT_REASON
+            )
         }
 
         val senderKey = olmEventContent.senderKey ?: run {
             Timber.tag(loggerTag.value).e("## decryptEvent() : missing sender key")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_SENDER_KEY,
-                    MXCryptoError.MISSING_SENDER_KEY_TEXT_REASON)
+            throw MXCryptoError.Base(
+                    MXCryptoError.ErrorType.MISSING_SENDER_KEY,
+                    MXCryptoError.MISSING_SENDER_KEY_TEXT_REASON
+            )
         }
 
         val messageAny = cipherText[olmDevice.deviceCurve25519Key] ?: run {
@@ -98,52 +104,70 @@ internal class MXOlmDecryption(
         }
 
         if (olmPayloadContent.recipient != userId) {
-            Timber.tag(loggerTag.value).e("## decryptEvent() : Event ${event.eventId}:" +
-                    " Intended recipient ${olmPayloadContent.recipient} does not match our id $userId")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_RECIPIENT,
-                    String.format(MXCryptoError.BAD_RECIPIENT_REASON, olmPayloadContent.recipient))
+            Timber.tag(loggerTag.value).e(
+                    "## decryptEvent() : Event ${event.eventId}:" +
+                            " Intended recipient ${olmPayloadContent.recipient} does not match our id $userId"
+            )
+            throw MXCryptoError.Base(
+                    MXCryptoError.ErrorType.BAD_RECIPIENT,
+                    String.format(MXCryptoError.BAD_RECIPIENT_REASON, olmPayloadContent.recipient)
+            )
         }
 
         val recipientKeys = olmPayloadContent.recipientKeys ?: run {
-            Timber.tag(loggerTag.value).e("## decryptEvent() : Olm event (id=${event.eventId}) contains no 'recipient_keys'" +
-                    " property; cannot prevent unknown-key attack")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_PROPERTY,
-                    String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "recipient_keys"))
+            Timber.tag(loggerTag.value).e(
+                    "## decryptEvent() : Olm event (id=${event.eventId}) contains no 'recipient_keys'" +
+                            " property; cannot prevent unknown-key attack"
+            )
+            throw MXCryptoError.Base(
+                    MXCryptoError.ErrorType.MISSING_PROPERTY,
+                    String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "recipient_keys")
+            )
         }
 
         val ed25519 = recipientKeys["ed25519"]
 
         if (ed25519 != olmDevice.deviceEd25519Key) {
             Timber.tag(loggerTag.value).e("## decryptEvent() : Event ${event.eventId}: Intended recipient ed25519 key $ed25519 did not match ours")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_RECIPIENT_KEY,
-                    MXCryptoError.BAD_RECIPIENT_KEY_REASON)
+            throw MXCryptoError.Base(
+                    MXCryptoError.ErrorType.BAD_RECIPIENT_KEY,
+                    MXCryptoError.BAD_RECIPIENT_KEY_REASON
+            )
         }
 
         if (olmPayloadContent.sender.isNullOrBlank()) {
             Timber.tag(loggerTag.value)
                     .e("## decryptEvent() : Olm event (id=${event.eventId}) contains no 'sender' property; cannot prevent unknown-key attack")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_PROPERTY,
-                    String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "sender"))
+            throw MXCryptoError.Base(
+                    MXCryptoError.ErrorType.MISSING_PROPERTY,
+                    String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "sender")
+            )
         }
 
         if (olmPayloadContent.sender != event.senderId) {
             Timber.tag(loggerTag.value)
                     .e("Event ${event.eventId}:  sender ${olmPayloadContent.sender} does not match reported sender ${event.senderId}")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.FORWARDED_MESSAGE,
-                    String.format(MXCryptoError.FORWARDED_MESSAGE_REASON, olmPayloadContent.sender))
+            throw MXCryptoError.Base(
+                    MXCryptoError.ErrorType.FORWARDED_MESSAGE,
+                    String.format(MXCryptoError.FORWARDED_MESSAGE_REASON, olmPayloadContent.sender)
+            )
         }
 
         if (olmPayloadContent.roomId != event.roomId) {
             Timber.tag(loggerTag.value)
                     .e("## decryptEvent() : Event ${event.eventId}:  room ${olmPayloadContent.roomId} does not match reported room ${event.roomId}")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ROOM,
-                    String.format(MXCryptoError.BAD_ROOM_REASON, olmPayloadContent.roomId))
+            throw MXCryptoError.Base(
+                    MXCryptoError.ErrorType.BAD_ROOM,
+                    String.format(MXCryptoError.BAD_ROOM_REASON, olmPayloadContent.roomId)
+            )
         }
 
         val keys = olmPayloadContent.keys ?: run {
             Timber.tag(loggerTag.value).e("## decryptEvent failed : null keys")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT,
-                    MXCryptoError.MISSING_CIPHER_TEXT_REASON)
+            throw MXCryptoError.Base(
+                    MXCryptoError.ErrorType.UNABLE_TO_DECRYPT,
+                    MXCryptoError.MISSING_CIPHER_TEXT_REASON
+            )
         }
 
         return MXEventDecryptionResult(
@@ -241,8 +265,4 @@ internal class MXOlmDecryption(
 
         return res["payload"]
     }
-
-    override fun requestKeysForEvent(event: Event, withHeld: Boolean) {
-        // nop
-    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt
index 972176e25b7bd3357e5d26231201a0a742c39521..d5c5e85e41a1e37ed5ff6874fb040f47666edb4b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt
@@ -26,6 +26,7 @@ internal class MXOlmDecryptionFactory @Inject constructor(private val olmDevice:
     fun create(): MXOlmDecryption {
         return MXOlmDecryption(
                 olmDevice,
-                userId)
+                userId
+        )
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryption.kt
index c842c5404151adbcce729b5f4fc24f1d1559c81e..3c9706abe18e31ddadeb5c39cf9b8332cf65c895 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryption.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryption.kt
@@ -38,7 +38,7 @@ internal class MXOlmEncryption(
     override suspend fun encryptEventContent(eventContent: Content, eventType: String, userIds: List<String>): Content {
         // pick the list of recipients based on the membership list.
         //
-        // TODO: there is a race condition here! What if a new user turns up
+        // TODO there is a race condition here! What if a new user turns up
         ensureSession(userIds)
         val deviceInfos = ArrayList<CryptoDeviceInfo>()
         for (userId in userIds) {
@@ -68,7 +68,7 @@ internal class MXOlmEncryption(
     }
 
     /**
-     * Ensure that the session
+     * Ensure that the session.
      *
      * @param users    the user ids list
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt
index 50ce2d2bf3d02a65f509b3e05b7b0998950000a8..44e55900e4ada7db382ba541a5c51989a72a3d68 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt
@@ -38,6 +38,7 @@ internal class MXOlmEncryptionFactory @Inject constructor(private val olmDevice:
                 cryptoStore,
                 messageEncrypter,
                 deviceListManager,
-                ensureOlmSessionsForUsersAction)
+                ensureOlmSessionsForUsersAction
+        )
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/EncryptionResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/EncryptionResult.kt
index 80090cf4a8a4612dbe698cc9dfa738fe772747e4..95254bd67987bdb9643e53d0eaac73dc92dd6a78 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/EncryptionResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/EncryptionResult.kt
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.crypto.attachments
 import org.matrix.android.sdk.api.session.crypto.model.EncryptedFileInfo
 
 /**
- * Define the result of an encryption file
+ * Define the result of an encryption file.
  */
 internal data class EncryptionResult(
         val encryptedFileInfo: EncryptedFileInfo,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt
index 65bbb0c4125ef7f5a2f50a5fa1d51f10c75cc4c3..b4cbd15109b5ca457ee426472dc50f7a319aa69c 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt
@@ -227,7 +227,7 @@ internal object MXEncryptedAttachments {
     }
 
     /**
-     * Decrypt an attachment
+     * Decrypt an attachment.
      *
      * @param attachmentStream the attachment stream. Will be closed after this method call.
      * @param elementToDecrypt the elementToDecrypt info
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4fa355cd2a787511b5463d9abf70e526a35a3376
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.internal.crypto.crosssigning
+
+import org.matrix.android.sdk.api.util.JsonDict
+import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
+import org.matrix.android.sdk.internal.session.SessionScope
+import org.matrix.android.sdk.internal.util.JsonCanonicalizer
+import org.matrix.olm.OlmPkSigning
+import org.matrix.olm.OlmUtility
+import javax.inject.Inject
+
+/**
+ * Holds the OlmPkSigning for cross signing.
+ * Can be injected without having to get the full cross signing service
+ */
+@SessionScope
+internal class CrossSigningOlm @Inject constructor(
+        private val cryptoStore: IMXCryptoStore,
+) {
+
+    enum class KeyType {
+        SELF,
+        USER,
+        MASTER
+    }
+
+    var olmUtility: OlmUtility = OlmUtility()
+
+    var masterPkSigning: OlmPkSigning? = null
+    var userPkSigning: OlmPkSigning? = null
+    var selfSigningPkSigning: OlmPkSigning? = null
+
+    fun release() {
+        olmUtility.releaseUtility()
+        listOf(masterPkSigning, userPkSigning, selfSigningPkSigning).forEach { it?.releaseSigning() }
+    }
+
+    fun signObject(type: KeyType, strToSign: String): Map<String, String> {
+        val myKeys = cryptoStore.getMyCrossSigningInfo()
+        val pubKey = when (type) {
+            KeyType.SELF   -> myKeys?.selfSigningKey()
+            KeyType.USER   -> myKeys?.userKey()
+            KeyType.MASTER -> myKeys?.masterKey()
+        }?.unpaddedBase64PublicKey
+        val pkSigning = when (type) {
+            KeyType.SELF   -> selfSigningPkSigning
+            KeyType.USER   -> userPkSigning
+            KeyType.MASTER -> masterPkSigning
+        }
+        if (pubKey == null || pkSigning == null) {
+            throw Throwable("Cannot sign from this account, public and/or privateKey Unknown $type|$pkSigning")
+        }
+        val signature = pkSigning.sign(strToSign)
+        return mapOf(
+                "ed25519:$pubKey" to signature
+        )
+    }
+
+    fun verifySignature(type: KeyType, signable: JsonDict, signatures: Map<String, Map<String, String>>) {
+        val myKeys = cryptoStore.getMyCrossSigningInfo()
+                ?: throw NoSuchElementException("Cross Signing not configured")
+        val myUserID = myKeys.userId
+        val pubKey = when (type) {
+            KeyType.SELF   -> myKeys.selfSigningKey()
+            KeyType.USER   -> myKeys.userKey()
+            KeyType.MASTER -> myKeys.masterKey()
+        }?.unpaddedBase64PublicKey ?: throw NoSuchElementException("Cross Signing not configured")
+        val signaturesMadeByMyKey = signatures[myUserID] // Signatures made by me
+                ?.get("ed25519:$pubKey")
+
+        if (signaturesMadeByMyKey.isNullOrBlank()) {
+            throw IllegalArgumentException("Not signed with my key $type")
+        }
+
+        // Check that Alice USK signature of Bob MSK is valid
+        olmUtility.verifyEd25519Signature(signaturesMadeByMyKey, pubKey, JsonCanonicalizer.getCanonicalJson(Map::class.java, signable))
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
index ba1718688fd33c907d552a80d588e77d6df61ff5..6c198abc2ed7db270b448dca000cb632468f3095 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
@@ -38,6 +38,7 @@ import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
 import org.matrix.android.sdk.api.util.Optional
 import org.matrix.android.sdk.api.util.fromBase64
 import org.matrix.android.sdk.internal.crypto.DeviceListManager
+import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
 import org.matrix.android.sdk.internal.crypto.model.rest.UploadSignatureQueryBuilder
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import org.matrix.android.sdk.internal.crypto.tasks.InitializeCrossSigningTask
@@ -53,7 +54,6 @@ import org.matrix.android.sdk.internal.util.JsonCanonicalizer
 import org.matrix.android.sdk.internal.util.logLimit
 import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
 import org.matrix.olm.OlmPkSigning
-import org.matrix.olm.OlmUtility
 import timber.log.Timber
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
@@ -70,19 +70,14 @@ internal class DefaultCrossSigningService @Inject constructor(
         private val coroutineDispatchers: MatrixCoroutineDispatchers,
         private val cryptoCoroutineScope: CoroutineScope,
         private val workManagerProvider: WorkManagerProvider,
+        private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
+        private val crossSigningOlm: CrossSigningOlm,
         private val updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository
 ) : CrossSigningService,
         DeviceListManager.UserDevicesUpdateListener {
 
-    private var olmUtility: OlmUtility? = null
-
-    private var masterPkSigning: OlmPkSigning? = null
-    private var userPkSigning: OlmPkSigning? = null
-    private var selfSigningPkSigning: OlmPkSigning? = null
-
     init {
         try {
-            olmUtility = OlmUtility()
 
             // Try to get stored keys if they exist
             cryptoStore.getMyCrossSigningInfo()?.let { mxCrossSigningInfo ->
@@ -95,7 +90,7 @@ internal class DefaultCrossSigningService @Inject constructor(
                             ?.let { privateKeySeed ->
                                 val pkSigning = OlmPkSigning()
                                 if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.masterKey()?.unpaddedBase64PublicKey) {
-                                    masterPkSigning = pkSigning
+                                    crossSigningOlm.masterPkSigning = pkSigning
                                     Timber.i("## CrossSigning - Loading master key success")
                                 } else {
                                     Timber.w("## CrossSigning - Public master key does not match the private key")
@@ -108,7 +103,7 @@ internal class DefaultCrossSigningService @Inject constructor(
                             ?.let { privateKeySeed ->
                                 val pkSigning = OlmPkSigning()
                                 if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.userKey()?.unpaddedBase64PublicKey) {
-                                    userPkSigning = pkSigning
+                                    crossSigningOlm.userPkSigning = pkSigning
                                     Timber.i("## CrossSigning - Loading User Signing key success")
                                 } else {
                                     Timber.w("## CrossSigning - Public User key does not match the private key")
@@ -121,7 +116,7 @@ internal class DefaultCrossSigningService @Inject constructor(
                             ?.let { privateKeySeed ->
                                 val pkSigning = OlmPkSigning()
                                 if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.selfSigningKey()?.unpaddedBase64PublicKey) {
-                                    selfSigningPkSigning = pkSigning
+                                    crossSigningOlm.selfSigningPkSigning = pkSigning
                                     Timber.i("## CrossSigning - Loading Self Signing key success")
                                 } else {
                                     Timber.w("## CrossSigning - Public Self Signing key does not match the private key")
@@ -143,8 +138,7 @@ internal class DefaultCrossSigningService @Inject constructor(
     }
 
     fun release() {
-        olmUtility?.releaseUtility()
-        listOf(masterPkSigning, userPkSigning, selfSigningPkSigning).forEach { it?.releaseSigning() }
+        crossSigningOlm.release()
         deviceListManager.removeListener(this)
     }
 
@@ -153,10 +147,10 @@ internal class DefaultCrossSigningService @Inject constructor(
     }
 
     /**
-     *   - Make 3 key pairs (MSK, USK, SSK)
-     *   - Save the private keys with proper security
-     *   - Sign the keys and upload them
-     *   - Sign the current device with SSK and sign MSK with device key (migration) and upload signatures
+     * - Make 3 key pairs (MSK, USK, SSK)
+     * - Save the private keys with proper security
+     * - Sign the keys and upload them
+     * - Sign the current device with SSK and sign MSK with device key (migration) and upload signatures.
      */
     override fun initializeCrossSigning(uiaInterceptor: UserInteractiveAuthInterceptor?, callback: MatrixCallback<Unit>) {
         Timber.d("## CrossSigning  initializeCrossSigning")
@@ -177,9 +171,9 @@ internal class DefaultCrossSigningService @Inject constructor(
                     cryptoStore.setMyCrossSigningInfo(crossSigningInfo)
                     setUserKeysAsTrusted(userId, true)
                     cryptoStore.storePrivateKeysInfo(data.masterKeyPK, data.userKeyPK, data.selfSigningKeyPK)
-                    masterPkSigning = OlmPkSigning().apply { initWithSeed(data.masterKeyPK.fromBase64()) }
-                    userPkSigning = OlmPkSigning().apply { initWithSeed(data.userKeyPK.fromBase64()) }
-                    selfSigningPkSigning = OlmPkSigning().apply { initWithSeed(data.selfSigningKeyPK.fromBase64()) }
+                    crossSigningOlm.masterPkSigning = OlmPkSigning().apply { initWithSeed(data.masterKeyPK.fromBase64()) }
+                    crossSigningOlm.userPkSigning = OlmPkSigning().apply { initWithSeed(data.userKeyPK.fromBase64()) }
+                    crossSigningOlm.selfSigningPkSigning = OlmPkSigning().apply { initWithSeed(data.selfSigningKeyPK.fromBase64()) }
 
                     callback.onSuccess(Unit)
                 }
@@ -198,8 +192,8 @@ internal class DefaultCrossSigningService @Inject constructor(
                     val pkSigning = OlmPkSigning()
                     try {
                         if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.masterKey()?.unpaddedBase64PublicKey) {
-                            masterPkSigning?.releaseSigning()
-                            masterPkSigning = pkSigning
+                            crossSigningOlm.masterPkSigning?.releaseSigning()
+                            crossSigningOlm.masterPkSigning = pkSigning
                             Timber.i("## CrossSigning - Loading MSK success")
                             cryptoStore.storeMSKPrivateKey(mskPrivateKey)
                             return
@@ -225,8 +219,8 @@ internal class DefaultCrossSigningService @Inject constructor(
                     val pkSigning = OlmPkSigning()
                     try {
                         if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.selfSigningKey()?.unpaddedBase64PublicKey) {
-                            selfSigningPkSigning?.releaseSigning()
-                            selfSigningPkSigning = pkSigning
+                            crossSigningOlm.selfSigningPkSigning?.releaseSigning()
+                            crossSigningOlm.selfSigningPkSigning = pkSigning
                             Timber.i("## CrossSigning - Loading SSK success")
                             cryptoStore.storeSSKPrivateKey(sskPrivateKey)
                             return
@@ -252,8 +246,8 @@ internal class DefaultCrossSigningService @Inject constructor(
                     val pkSigning = OlmPkSigning()
                     try {
                         if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.userKey()?.unpaddedBase64PublicKey) {
-                            userPkSigning?.releaseSigning()
-                            userPkSigning = pkSigning
+                            crossSigningOlm.userPkSigning?.releaseSigning()
+                            crossSigningOlm.userPkSigning = pkSigning
                             Timber.i("## CrossSigning - Loading USK success")
                             cryptoStore.storeUSKPrivateKey(uskPrivateKey)
                             return
@@ -282,8 +276,8 @@ internal class DefaultCrossSigningService @Inject constructor(
                     val pkSigning = OlmPkSigning()
                     try {
                         if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.masterKey()?.unpaddedBase64PublicKey) {
-                            masterPkSigning?.releaseSigning()
-                            masterPkSigning = pkSigning
+                            crossSigningOlm.masterPkSigning?.releaseSigning()
+                            crossSigningOlm.masterPkSigning = pkSigning
                             masterKeyIsTrusted = true
                             Timber.i("## CrossSigning - Loading master key success")
                         } else {
@@ -299,8 +293,8 @@ internal class DefaultCrossSigningService @Inject constructor(
                     val pkSigning = OlmPkSigning()
                     try {
                         if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.userKey()?.unpaddedBase64PublicKey) {
-                            userPkSigning?.releaseSigning()
-                            userPkSigning = pkSigning
+                            crossSigningOlm.userPkSigning?.releaseSigning()
+                            crossSigningOlm.userPkSigning = pkSigning
                             userKeyIsTrusted = true
                             Timber.i("## CrossSigning - Loading master key success")
                         } else {
@@ -316,8 +310,8 @@ internal class DefaultCrossSigningService @Inject constructor(
                     val pkSigning = OlmPkSigning()
                     try {
                         if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.selfSigningKey()?.unpaddedBase64PublicKey) {
-                            selfSigningPkSigning?.releaseSigning()
-                            selfSigningPkSigning = pkSigning
+                            crossSigningOlm.selfSigningPkSigning?.releaseSigning()
+                            crossSigningOlm.selfSigningPkSigning = pkSigning
                             selfSignedKeyIsTrusted = true
                             Timber.i("## CrossSigning - Loading master key success")
                         } else {
@@ -353,6 +347,7 @@ internal class DefaultCrossSigningService @Inject constructor(
      *     │                      │
      *     │                      │
      *     └──▶ USK   ────────────┘
+     * .
      */
     override fun isUserTrusted(otherUserId: String): Boolean {
         return cryptoStore.getCrossSigningInfo(userId)?.isTrusted() == true
@@ -363,7 +358,7 @@ internal class DefaultCrossSigningService @Inject constructor(
     }
 
     /**
-     * Will not force a download of the key, but will verify signatures trust chain
+     * Will not force a download of the key, but will verify signatures trust chain.
      */
     override fun checkUserTrust(otherUserId: String): UserTrustResult {
         Timber.v("## CrossSigning  checkUserTrust for $otherUserId")
@@ -405,7 +400,11 @@ internal class DefaultCrossSigningService @Inject constructor(
 
         // Check that Alice USK signature of Bob MSK is valid
         try {
-            olmUtility!!.verifyEd25519Signature(masterKeySignaturesMadeByMyUserKey, myUserKey.unpaddedBase64PublicKey, otherMasterKey.canonicalSignable())
+            crossSigningOlm.olmUtility.verifyEd25519Signature(
+                    masterKeySignaturesMadeByMyUserKey,
+                    myUserKey.unpaddedBase64PublicKey,
+                    otherMasterKey.canonicalSignable()
+            )
         } catch (failure: Throwable) {
             return UserTrustResult.InvalidSignature(myUserKey, masterKeySignaturesMadeByMyUserKey)
         }
@@ -459,7 +458,7 @@ internal class DefaultCrossSigningService @Inject constructor(
                 if (potentialDevice != null && potentialDevice.isVerified) {
                     // Check signature validity?
                     try {
-                        olmUtility?.verifyEd25519Signature(value, potentialDevice.fingerprint(), myMasterKey.canonicalSignable())
+                        crossSigningOlm.olmUtility.verifyEd25519Signature(value, potentialDevice.fingerprint(), myMasterKey.canonicalSignable())
                         isMaterKeyTrusted = true
                         return@forEach
                     } catch (failure: Throwable) {
@@ -488,7 +487,11 @@ internal class DefaultCrossSigningService @Inject constructor(
 
         // Check that Alice USK signature of Alice MSK is valid
         try {
-            olmUtility!!.verifyEd25519Signature(userKeySignaturesMadeByMyMasterKey, myMasterKey.unpaddedBase64PublicKey, myUserKey.canonicalSignable())
+            crossSigningOlm.olmUtility.verifyEd25519Signature(
+                    userKeySignaturesMadeByMyMasterKey,
+                    myMasterKey.unpaddedBase64PublicKey,
+                    myUserKey.canonicalSignable()
+            )
         } catch (failure: Throwable) {
             return UserTrustResult.InvalidSignature(myUserKey, userKeySignaturesMadeByMyMasterKey)
         }
@@ -507,7 +510,11 @@ internal class DefaultCrossSigningService @Inject constructor(
 
         // Check that Alice USK signature of Alice MSK is valid
         try {
-            olmUtility!!.verifyEd25519Signature(ssKeySignaturesMadeByMyMasterKey, myMasterKey.unpaddedBase64PublicKey, mySSKey.canonicalSignable())
+            crossSigningOlm.olmUtility.verifyEd25519Signature(
+                    ssKeySignaturesMadeByMyMasterKey,
+                    myMasterKey.unpaddedBase64PublicKey,
+                    mySSKey.canonicalSignable()
+            )
         } catch (failure: Throwable) {
             return UserTrustResult.InvalidSignature(mySSKey, ssKeySignaturesMadeByMyMasterKey)
         }
@@ -560,14 +567,16 @@ internal class DefaultCrossSigningService @Inject constructor(
                 return@launch
             }
             val userPubKey = myKeys.userKey()?.unpaddedBase64PublicKey
-            if (userPubKey == null || userPkSigning == null) {
+            if (userPubKey == null || crossSigningOlm.userPkSigning == null) {
                 callback.onFailure(Throwable("## CrossSigning - Cannot sign from this account, privateKeyUnknown $userPubKey"))
                 return@launch
             }
 
             // Sign the other MasterKey with our UserSigning key
-            val newSignature = JsonCanonicalizer.getCanonicalJson(Map::class.java,
-                    otherMasterKeys.signalableJSONDictionary()).let { userPkSigning?.sign(it) }
+            val newSignature = JsonCanonicalizer.getCanonicalJson(
+                    Map::class.java,
+                    otherMasterKeys.signalableJSONDictionary()
+            ).let { crossSigningOlm.userPkSigning?.sign(it) }
 
             if (newSignature == null) {
                 // race??
@@ -614,13 +623,13 @@ internal class DefaultCrossSigningService @Inject constructor(
             }
 
             val ssPubKey = myKeys.selfSigningKey()?.unpaddedBase64PublicKey
-            if (ssPubKey == null || selfSigningPkSigning == null) {
+            if (ssPubKey == null || crossSigningOlm.selfSigningPkSigning == null) {
                 callback.onFailure(Throwable("Cannot sign from this account, public and/or privateKey Unknown $ssPubKey"))
                 return@launch
             }
 
             // Sign with self signing
-            val newSignature = selfSigningPkSigning?.sign(device.canonicalSignable())
+            val newSignature = crossSigningOlm.selfSigningPkSigning?.sign(device.canonicalSignable())
 
             if (newSignature == null) {
                 // race??
@@ -684,7 +693,8 @@ internal class DefaultCrossSigningService @Inject constructor(
         val otherSSKSignature = otherDevice.signatures?.get(otherUserId)?.get("ed25519:${otherKeys.selfSigningKey()?.unpaddedBase64PublicKey}")
                 ?: return legacyFallbackTrust(
                         locallyTrusted,
-                        DeviceTrustResult.MissingDeviceSignature(otherDeviceId, otherKeys.selfSigningKey()
+                        DeviceTrustResult.MissingDeviceSignature(
+                                otherDeviceId, otherKeys.selfSigningKey()
                                 ?.unpaddedBase64PublicKey
                                 ?: ""
                         )
@@ -692,7 +702,11 @@ internal class DefaultCrossSigningService @Inject constructor(
 
         // Check  bob's device is signed by bob's SSK
         try {
-            olmUtility!!.verifyEd25519Signature(otherSSKSignature, otherKeys.selfSigningKey()?.unpaddedBase64PublicKey, otherDevice.canonicalSignable())
+            crossSigningOlm.olmUtility.verifyEd25519Signature(
+                    otherSSKSignature,
+                    otherKeys.selfSigningKey()?.unpaddedBase64PublicKey,
+                    otherDevice.canonicalSignable()
+            )
         } catch (e: Throwable) {
             return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.InvalidDeviceSignature(otherDeviceId, otherSSKSignature, e))
         }
@@ -733,7 +747,8 @@ internal class DefaultCrossSigningService @Inject constructor(
         val otherSSKSignature = otherDevice.signatures?.get(otherKeys.userId)?.get("ed25519:${otherKeys.selfSigningKey()?.unpaddedBase64PublicKey}")
                 ?: return legacyFallbackTrust(
                         locallyTrusted,
-                        DeviceTrustResult.MissingDeviceSignature(otherDevice.deviceId, otherKeys.selfSigningKey()
+                        DeviceTrustResult.MissingDeviceSignature(
+                                otherDevice.deviceId, otherKeys.selfSigningKey()
                                 ?.unpaddedBase64PublicKey
                                 ?: ""
                         )
@@ -741,7 +756,11 @@ internal class DefaultCrossSigningService @Inject constructor(
 
         // Check  bob's device is signed by bob's SSK
         try {
-            olmUtility!!.verifyEd25519Signature(otherSSKSignature, otherKeys.selfSigningKey()?.unpaddedBase64PublicKey, otherDevice.canonicalSignable())
+            crossSigningOlm.olmUtility.verifyEd25519Signature(
+                    otherSSKSignature,
+                    otherKeys.selfSigningKey()?.unpaddedBase64PublicKey,
+                    otherDevice.canonicalSignable()
+            )
         } catch (e: Throwable) {
             return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.InvalidDeviceSignature(otherDevice.deviceId, otherSSKSignature, e))
         }
@@ -781,7 +800,8 @@ internal class DefaultCrossSigningService @Inject constructor(
         // If it's me, recheck trust of all users and devices?
         val users = ArrayList<String>()
         if (otherUserId == userId && currentTrust != trusted) {
-//                reRequestAllPendingRoomKeyRequest()
+            // notify key requester
+            outgoingKeyRequestManager.onSelfCrossSigningTrustChanged(trusted)
             cryptoStore.updateUsersTrust {
                 users.add(it)
                 checkUserTrust(it).isVerified()
@@ -796,19 +816,4 @@ internal class DefaultCrossSigningService @Inject constructor(
             }
         }
     }
-
-//    private fun reRequestAllPendingRoomKeyRequest() {
-//        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
-//            Timber.d("## CrossSigning - reRequest pending outgoing room key requests")
-//            cryptoStore.getOutgoingRoomKeyRequests().forEach {
-//                it.requestBody?.let { requestBody ->
-//                    if (cryptoStore.getInboundGroupSession(requestBody.sessionId ?: "", requestBody.senderKey ?: "") == null) {
-//                        outgoingRoomKeyRequestManager.resendRoomKeyRequest(requestBody)
-//                    } else {
-//                        outgoingRoomKeyRequestManager.cancelRoomKeyRequest(requestBody)
-//                    }
-//                }
-//            }
-//        }
-//    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt
index e63a6dc791c2a541688380de45c3eb9f57bd1374..5ea4695da29b4bcf73a372cc338c6b88909db9b2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt
@@ -54,6 +54,7 @@ import org.matrix.android.sdk.internal.crypto.MXOlmDevice
 import org.matrix.android.sdk.internal.crypto.MegolmSessionData
 import org.matrix.android.sdk.internal.crypto.ObjectSigner
 import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
+import org.matrix.android.sdk.internal.crypto.crosssigning.CrossSigningOlm
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.SignalableMegolmBackupAuthData
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.BackupKeysResult
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.CreateKeysBackupVersionBody
@@ -63,16 +64,11 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.RoomKeysBack
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.UpdateKeysBackupVersionBody
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.CreateKeysBackupVersionTask
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DeleteBackupTask
-import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DeleteRoomSessionDataTask
-import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DeleteRoomSessionsDataTask
-import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DeleteSessionsDataTask
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetKeysBackupLastVersionTask
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetKeysBackupVersionTask
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetRoomSessionDataTask
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetRoomSessionsDataTask
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetSessionsDataTask
-import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreRoomSessionDataTask
-import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreRoomSessionsDataTask
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreSessionsDataTask
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.UpdateKeysBackupVersionTask
 import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
@@ -107,21 +103,17 @@ internal class DefaultKeysBackupService @Inject constructor(
         private val cryptoStore: IMXCryptoStore,
         private val olmDevice: MXOlmDevice,
         private val objectSigner: ObjectSigner,
+        private val crossSigningOlm: CrossSigningOlm,
         // Actions
         private val megolmSessionDataImporter: MegolmSessionDataImporter,
         // Tasks
         private val createKeysBackupVersionTask: CreateKeysBackupVersionTask,
         private val deleteBackupTask: DeleteBackupTask,
-        private val deleteRoomSessionDataTask: DeleteRoomSessionDataTask,
-        private val deleteRoomSessionsDataTask: DeleteRoomSessionsDataTask,
-        private val deleteSessionDataTask: DeleteSessionsDataTask,
         private val getKeysBackupLastVersionTask: GetKeysBackupLastVersionTask,
         private val getKeysBackupVersionTask: GetKeysBackupVersionTask,
         private val getRoomSessionDataTask: GetRoomSessionDataTask,
         private val getRoomSessionsDataTask: GetRoomSessionsDataTask,
         private val getSessionsDataTask: GetSessionsDataTask,
-        private val storeRoomSessionDataTask: StoreRoomSessionDataTask,
-        private val storeSessionsDataTask: StoreRoomSessionsDataTask,
         private val storeSessionDataTask: StoreSessionsDataTask,
         private val updateKeysBackupVersionTask: UpdateKeysBackupVersionTask,
         // Task executor
@@ -168,58 +160,76 @@ internal class DefaultKeysBackupService @Inject constructor(
     override fun prepareKeysBackupVersion(password: String?,
                                           progressListener: ProgressListener?,
                                           callback: MatrixCallback<MegolmBackupCreationInfo>) {
-        cryptoCoroutineScope.launch(coroutineDispatchers.main) {
-            runCatching {
-                withContext(coroutineDispatchers.crypto) {
-                    val olmPkDecryption = OlmPkDecryption()
-                    val signalableMegolmBackupAuthData = if (password != null) {
-                        // Generate a private key from the password
-                        val backgroundProgressListener = if (progressListener == null) {
-                            null
-                        } else {
-                            object : ProgressListener {
-                                override fun onProgress(progress: Int, total: Int) {
-                                    uiHandler.post {
-                                        try {
-                                            progressListener.onProgress(progress, total)
-                                        } catch (e: Exception) {
-                                            Timber.e(e, "prepareKeysBackupVersion: onProgress failure")
-                                        }
+        cryptoCoroutineScope.launch(coroutineDispatchers.io) {
+            try {
+                val olmPkDecryption = OlmPkDecryption()
+                val signalableMegolmBackupAuthData = if (password != null) {
+                    // Generate a private key from the password
+                    val backgroundProgressListener = if (progressListener == null) {
+                        null
+                    } else {
+                        object : ProgressListener {
+                            override fun onProgress(progress: Int, total: Int) {
+                                uiHandler.post {
+                                    try {
+                                        progressListener.onProgress(progress, total)
+                                    } catch (e: Exception) {
+                                        Timber.e(e, "prepareKeysBackupVersion: onProgress failure")
                                     }
                                 }
                             }
                         }
+                    }
+                    val generatePrivateKeyResult = generatePrivateKeyWithPassword(password, backgroundProgressListener)
+                    SignalableMegolmBackupAuthData(
+                            publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey),
+                            privateKeySalt = generatePrivateKeyResult.salt,
+                            privateKeyIterations = generatePrivateKeyResult.iterations
+                    )
+                } else {
+                    val publicKey = olmPkDecryption.generateKey()
+                    SignalableMegolmBackupAuthData(
+                            publicKey = publicKey
+                    )
+                }
 
-                        val generatePrivateKeyResult = generatePrivateKeyWithPassword(password, backgroundProgressListener)
-                        SignalableMegolmBackupAuthData(
-                                publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey),
-                                privateKeySalt = generatePrivateKeyResult.salt,
-                                privateKeyIterations = generatePrivateKeyResult.iterations
-                        )
-                    } else {
-                        val publicKey = olmPkDecryption.generateKey()
+                val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableMegolmBackupAuthData.signalableJSONDictionary())
 
-                        SignalableMegolmBackupAuthData(
-                                publicKey = publicKey
-                        )
-                    }
+                val signatures = mutableMapOf<String, MutableMap<String, String>>()
 
-                    val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableMegolmBackupAuthData.signalableJSONDictionary())
+                val deviceSignature = objectSigner.signObject(canonicalJson)
+                deviceSignature.forEach { (userID, content) ->
+                    signatures[userID] = content.toMutableMap()
+                }
 
-                    val signedMegolmBackupAuthData = MegolmBackupAuthData(
-                            publicKey = signalableMegolmBackupAuthData.publicKey,
-                            privateKeySalt = signalableMegolmBackupAuthData.privateKeySalt,
-                            privateKeyIterations = signalableMegolmBackupAuthData.privateKeyIterations,
-                            signatures = objectSigner.signObject(canonicalJson)
-                    )
+                // If we have cross signing add signature, will throw if cross signing not properly configured
+                try {
+                    val crossSign = crossSigningOlm.signObject(CrossSigningOlm.KeyType.MASTER, canonicalJson)
+                    signatures[credentials.userId]?.putAll(crossSign)
+                } catch (failure: Throwable) {
+                    // ignore and log
+                    Timber.w(failure, "prepareKeysBackupVersion: failed to sign with cross signing keys")
+                }
 
-                    MegolmBackupCreationInfo(
-                            algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
-                            authData = signedMegolmBackupAuthData,
-                            recoveryKey = computeRecoveryKey(olmPkDecryption.privateKey())
-                    )
+                val signedMegolmBackupAuthData = MegolmBackupAuthData(
+                        publicKey = signalableMegolmBackupAuthData.publicKey,
+                        privateKeySalt = signalableMegolmBackupAuthData.privateKeySalt,
+                        privateKeyIterations = signalableMegolmBackupAuthData.privateKeyIterations,
+                        signatures = signatures
+                )
+                val creationInfo = MegolmBackupCreationInfo(
+                        algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
+                        authData = signedMegolmBackupAuthData,
+                        recoveryKey = computeRecoveryKey(olmPkDecryption.privateKey())
+                )
+                uiHandler.post {
+                    callback.onSuccess(creationInfo)
+                }
+            } catch (failure: Throwable) {
+                uiHandler.post {
+                    callback.onFailure(failure)
                 }
-            }.foldToCallback(callback)
+            }
         }
     }
 
@@ -267,41 +277,39 @@ internal class DefaultKeysBackupService @Inject constructor(
     }
 
     override fun deleteBackup(version: String, callback: MatrixCallback<Unit>?) {
-        cryptoCoroutineScope.launch(coroutineDispatchers.main) {
-            withContext(coroutineDispatchers.crypto) {
-                // If we're currently backing up to this backup... stop.
-                // (We start using it automatically in createKeysBackupVersion so this is symmetrical).
-                if (keysBackupVersion != null && version == keysBackupVersion?.version) {
-                    resetKeysBackupData()
-                    keysBackupVersion = null
-                    keysBackupStateManager.state = KeysBackupState.Unknown
-                }
+        cryptoCoroutineScope.launch(coroutineDispatchers.io) {
+            // If we're currently backing up to this backup... stop.
+            // (We start using it automatically in createKeysBackupVersion so this is symmetrical).
+            if (keysBackupVersion != null && version == keysBackupVersion?.version) {
+                resetKeysBackupData()
+                keysBackupVersion = null
+                keysBackupStateManager.state = KeysBackupState.Unknown
+            }
 
-                deleteBackupTask
-                        .configureWith(DeleteBackupTask.Params(version)) {
-                            this.callback = object : MatrixCallback<Unit> {
-                                private fun eventuallyRestartBackup() {
-                                    // Do not stay in KeysBackupState.Unknown but check what is available on the homeserver
-                                    if (state == KeysBackupState.Unknown) {
-                                        checkAndStartKeysBackup()
-                                    }
+            deleteBackupTask
+                    .configureWith(DeleteBackupTask.Params(version)) {
+                        this.callback = object : MatrixCallback<Unit> {
+                            private fun eventuallyRestartBackup() {
+                                // Do not stay in KeysBackupState.Unknown but check what is available on the homeserver
+                                if (state == KeysBackupState.Unknown) {
+                                    checkAndStartKeysBackup()
                                 }
+                            }
 
-                                override fun onSuccess(data: Unit) {
-                                    eventuallyRestartBackup()
+                            override fun onSuccess(data: Unit) {
+                                eventuallyRestartBackup()
 
-                                    uiHandler.post { callback?.onSuccess(Unit) }
-                                }
+                                uiHandler.post { callback?.onSuccess(Unit) }
+                            }
 
-                                override fun onFailure(failure: Throwable) {
-                                    eventuallyRestartBackup()
+                            override fun onFailure(failure: Throwable) {
+                                eventuallyRestartBackup()
 
-                                    uiHandler.post { callback?.onFailure(failure) }
-                                }
+                                uiHandler.post { callback?.onFailure(failure) }
                             }
                         }
-                        .executeBy(taskExecutor)
-            }
+                    }
+                    .executeBy(taskExecutor)
         }
     }
 
@@ -339,6 +347,10 @@ internal class DefaultKeysBackupService @Inject constructor(
 
     override fun backupAllGroupSessions(progressListener: ProgressListener?,
                                         callback: MatrixCallback<Unit>?) {
+        if (!isEnabled || backupOlmPkEncryption == null || keysBackupVersion == null) {
+            callback?.onFailure(Throwable("Backup not enabled"))
+            return
+        }
         // Get a status right now
         getBackupProgress(object : ProgressListener {
             override fun onProgress(progress: Int, total: Int) {
@@ -427,18 +439,41 @@ internal class DefaultKeysBackupService @Inject constructor(
 
         for ((keyId, mySignature) in mySigs) {
             // XXX: is this how we're supposed to get the device id?
-            var deviceId: String? = null
+            var deviceOrCrossSigningKeyId: String? = null
             val components = keyId.split(":")
             if (components.size == 2) {
-                deviceId = components[1]
+                deviceOrCrossSigningKeyId = components[1]
             }
 
-            if (deviceId != null) {
-                val device = cryptoStore.getUserDevice(userId, deviceId)
+            // Let's check if it's my master key
+            val myMSKPKey = cryptoStore.getMyCrossSigningInfo()?.masterKey()?.unpaddedBase64PublicKey
+            if (deviceOrCrossSigningKeyId == myMSKPKey) {
+                // we have to check if we can trust
+
+                var isSignatureValid = false
+                try {
+                    crossSigningOlm.verifySignature(CrossSigningOlm.KeyType.MASTER, authData.signalableJSONDictionary(), authData.signatures)
+                    isSignatureValid = true
+                } catch (failure: Throwable) {
+                    Timber.w(failure, "getKeysBackupTrust: Bad signature from my user MSK")
+                }
+                val mskTrusted = cryptoStore.getMyCrossSigningInfo()?.masterKey()?.trustLevel?.isVerified() == true
+                if (isSignatureValid && mskTrusted) {
+                    keysBackupVersionTrustIsUsable = true
+                }
+                val signature = KeysBackupVersionTrustSignature.UserSignature(
+                        keyId = deviceOrCrossSigningKeyId,
+                        cryptoCrossSigningKey = cryptoStore.getMyCrossSigningInfo()?.masterKey(),
+                        valid = isSignatureValid
+                )
+
+                keysBackupVersionTrustSignatures.add(signature)
+            } else if (deviceOrCrossSigningKeyId != null) {
+                val device = cryptoStore.getUserDevice(userId, deviceOrCrossSigningKeyId)
                 var isSignatureValid = false
 
                 if (device == null) {
-                    Timber.v("getKeysBackupTrust: Signature from unknown device $deviceId")
+                    Timber.v("getKeysBackupTrust: Signature from unknown device $deviceOrCrossSigningKeyId")
                 } else {
                     val fingerprint = device.fingerprint()
                     if (fingerprint != null) {
@@ -455,8 +490,8 @@ internal class DefaultKeysBackupService @Inject constructor(
                     }
                 }
 
-                val signature = KeysBackupVersionTrustSignature(
-                        deviceId = deviceId,
+                val signature = KeysBackupVersionTrustSignature.DeviceSignature(
+                        deviceId = deviceOrCrossSigningKeyId,
                         device = device,
                         valid = isSignatureValid,
                 )
@@ -480,10 +515,11 @@ internal class DefaultKeysBackupService @Inject constructor(
 
         if (authData == null) {
             Timber.w("trustKeyBackupVersion:trust: Key backup is missing required data")
-
-            callback.onFailure(IllegalArgumentException("Missing element"))
+            uiHandler.post {
+                callback.onFailure(IllegalArgumentException("Missing element"))
+            }
         } else {
-            cryptoCoroutineScope.launch(coroutineDispatchers.main) {
+            cryptoCoroutineScope.launch(coroutineDispatchers.io) {
                 val updateKeysBackupVersionBody = withContext(coroutineDispatchers.crypto) {
                     // Get current signatures, or create an empty set
                     val myUserSignatures = authData.signatures?.get(userId).orEmpty().toMutableMap()
@@ -516,7 +552,8 @@ internal class DefaultKeysBackupService @Inject constructor(
                     UpdateKeysBackupVersionBody(
                             algorithm = keysBackupVersion.algorithm,
                             authData = newMegolmBackupAuthDataWithNewSignature.toJsonDict(),
-                            version = keysBackupVersion.version)
+                            version = keysBackupVersion.version
+                    )
                 }
 
                 // And send it to the homeserver
@@ -535,11 +572,15 @@ internal class DefaultKeysBackupService @Inject constructor(
 
                                     checkAndStartWithKeysBackupVersion(newKeysBackupVersion)
 
-                                    callback.onSuccess(data)
+                                    uiHandler.post {
+                                        callback.onSuccess(data)
+                                    }
                                 }
 
                                 override fun onFailure(failure: Throwable) {
-                                    callback.onFailure(failure)
+                                    uiHandler.post {
+                                        callback.onFailure(failure)
+                                    }
                                 }
                             }
                         }
@@ -553,15 +594,14 @@ internal class DefaultKeysBackupService @Inject constructor(
                                                        callback: MatrixCallback<Unit>) {
         Timber.v("trustKeysBackupVersionWithRecoveryKey: version ${keysBackupVersion.version}")
 
-        cryptoCoroutineScope.launch(coroutineDispatchers.main) {
-            val isValid = withContext(coroutineDispatchers.crypto) {
-                isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)
-            }
+        cryptoCoroutineScope.launch(coroutineDispatchers.io) {
+            val isValid = isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)
 
             if (!isValid) {
                 Timber.w("trustKeyBackupVersionWithRecoveryKey: Invalid recovery key.")
-
-                callback.onFailure(IllegalArgumentException("Invalid recovery key or password"))
+                uiHandler.post {
+                    callback.onFailure(IllegalArgumentException("Invalid recovery key or password"))
+                }
             } else {
                 trustKeysBackupVersion(keysBackupVersion, true, callback)
             }
@@ -573,15 +613,14 @@ internal class DefaultKeysBackupService @Inject constructor(
                                                       callback: MatrixCallback<Unit>) {
         Timber.v("trustKeysBackupVersionWithPassphrase: version ${keysBackupVersion.version}")
 
-        cryptoCoroutineScope.launch(coroutineDispatchers.main) {
-            val recoveryKey = withContext(coroutineDispatchers.crypto) {
-                recoveryKeyFromPassword(password, keysBackupVersion, null)
-            }
+        cryptoCoroutineScope.launch(coroutineDispatchers.io) {
+            val recoveryKey = recoveryKeyFromPassword(password, keysBackupVersion, null)
 
             if (recoveryKey == null) {
                 Timber.w("trustKeysBackupVersionWithPassphrase: Key backup is missing required data")
-
-                callback.onFailure(IllegalArgumentException("Missing element"))
+                uiHandler.post {
+                    callback.onFailure(IllegalArgumentException("Missing element"))
+                }
             } else {
                 // Check trust using the recovery key
                 trustKeysBackupVersionWithRecoveryKey(keysBackupVersion, recoveryKey, callback)
@@ -592,30 +631,28 @@ internal class DefaultKeysBackupService @Inject constructor(
     override fun onSecretKeyGossip(secret: String) {
         Timber.i("## CrossSigning - onSecretKeyGossip")
 
-        cryptoCoroutineScope.launch(coroutineDispatchers.main) {
+        cryptoCoroutineScope.launch(coroutineDispatchers.io) {
             try {
-                when (val keysBackupLastVersionResult = getKeysBackupLastVersionTask.execute(Unit)) {
-                    KeysBackupLastVersionResult.NoKeysBackup  -> {
-                        Timber.d("No keys backup found")
-                    }
-                    is KeysBackupLastVersionResult.KeysBackup -> {
-                        val keysBackupVersion = keysBackupLastVersionResult.keysVersionResult
-                        val recoveryKey = computeRecoveryKey(secret.fromBase64())
-                        if (isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)) {
-                            awaitCallback<Unit> {
-                                trustKeysBackupVersion(keysBackupVersion, true, it)
-                            }
-                            val importResult = awaitCallback<ImportRoomKeysResult> {
-                                restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, null, null, null, it)
-                            }
-                            withContext(coroutineDispatchers.crypto) {
-                                cryptoStore.saveBackupRecoveryKey(recoveryKey, keysBackupVersion.version)
-                            }
-                            Timber.i("onSecretKeyGossip: Recovered keys $importResult")
-                        } else {
-                            Timber.e("onSecretKeyGossip: Recovery key is not valid ${keysBackupVersion.version}")
+                val keysBackupVersion = getKeysBackupLastVersionTask.execute(Unit).toKeysVersionResult()
+                        ?: return@launch Unit.also {
+                            Timber.d("Failed to get backup last version")
                         }
+                val recoveryKey = computeRecoveryKey(secret.fromBase64())
+                if (isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)) {
+                    awaitCallback<Unit> {
+                        trustKeysBackupVersion(keysBackupVersion, true, it)
+                    }
+                    // we don't want to start immediately downloading all as it can take very long
+
+//                    val importResult = awaitCallback<ImportRoomKeysResult> {
+//                        restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, null, null, null, it)
+//                    }
+                    withContext(coroutineDispatchers.crypto) {
+                        cryptoStore.saveBackupRecoveryKey(recoveryKey, keysBackupVersion.version)
                     }
+                    Timber.i("onSecretKeyGossip: saved valid backup key")
+                } else {
+                    Timber.e("onSecretKeyGossip: Recovery key is not valid ${keysBackupVersion.version}")
                 }
             } catch (failure: Throwable) {
                 Timber.e("onSecretKeyGossip: failed to trust key backup version ${keysBackupVersion?.version}")
@@ -624,7 +661,7 @@ internal class DefaultKeysBackupService @Inject constructor(
     }
 
     /**
-     * Get public key from a Recovery key
+     * Get public key from a Recovery key.
      *
      * @param recoveryKey the recovery key
      * @return the corresponding public key, from Olm
@@ -678,9 +715,9 @@ internal class DefaultKeysBackupService @Inject constructor(
                                             callback: MatrixCallback<ImportRoomKeysResult>) {
         Timber.v("restoreKeysWithRecoveryKey: From backup version: ${keysVersionResult.version}")
 
-        cryptoCoroutineScope.launch(coroutineDispatchers.main) {
+        cryptoCoroutineScope.launch(coroutineDispatchers.io) {
             runCatching {
-                val decryption = withContext(coroutineDispatchers.crypto) {
+                val decryption = withContext(coroutineDispatchers.computation) {
                     // Check if the recovery is valid before going any further
                     if (!isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysVersionResult)) {
                         Timber.e("restoreKeysWithRecoveryKey: Invalid recovery key for this keys version")
@@ -719,14 +756,18 @@ internal class DefaultKeysBackupService @Inject constructor(
                             }
                         }
                     }
-                    Timber.v("restoreKeysWithRecoveryKey: Decrypted ${sessionsData.size} keys out" +
-                            " of $sessionsFromHsCount from the backup store on the homeserver")
+                    Timber.v(
+                            "restoreKeysWithRecoveryKey: Decrypted ${sessionsData.size} keys out" +
+                                    " of $sessionsFromHsCount from the backup store on the homeserver"
+                    )
 
                     // Do not trigger a backup for them if they come from the backup version we are using
                     val backUp = keysVersionResult.version != keysBackupVersion?.version
                     if (backUp) {
-                        Timber.v("restoreKeysWithRecoveryKey: Those keys will be backed up" +
-                                " to backup version: ${keysBackupVersion?.version}")
+                        Timber.v(
+                                "restoreKeysWithRecoveryKey: Those keys will be backed up" +
+                                        " to backup version: ${keysBackupVersion?.version}"
+                        )
                     }
 
                     // Import them into the crypto store
@@ -749,7 +790,19 @@ internal class DefaultKeysBackupService @Inject constructor(
                     }
                     result
                 }
-            }.foldToCallback(callback)
+            }.foldToCallback(object : MatrixCallback<ImportRoomKeysResult> {
+                override fun onSuccess(data: ImportRoomKeysResult) {
+                    uiHandler.post {
+                        callback.onSuccess(data)
+                    }
+                }
+
+                override fun onFailure(failure: Throwable) {
+                    uiHandler.post {
+                        callback.onFailure(failure)
+                    }
+                }
+            })
         }
     }
 
@@ -761,7 +814,7 @@ internal class DefaultKeysBackupService @Inject constructor(
                                               callback: MatrixCallback<ImportRoomKeysResult>) {
         Timber.v("[MXKeyBackup] restoreKeyBackup with password: From backup version: ${keysBackupVersion.version}")
 
-        cryptoCoroutineScope.launch(coroutineDispatchers.main) {
+        cryptoCoroutineScope.launch(coroutineDispatchers.io) {
             runCatching {
                 val progressListener = if (stepProgressListener != null) {
                     object : ProgressListener {
@@ -786,13 +839,25 @@ internal class DefaultKeysBackupService @Inject constructor(
                         restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, roomId, sessionId, stepProgressListener, it)
                     }
                 }
-            }.foldToCallback(callback)
+            }.foldToCallback(object : MatrixCallback<ImportRoomKeysResult> {
+                override fun onSuccess(data: ImportRoomKeysResult) {
+                    uiHandler.post {
+                        callback.onSuccess(data)
+                    }
+                }
+
+                override fun onFailure(failure: Throwable) {
+                    uiHandler.post {
+                        callback.onFailure(failure)
+                    }
+                }
+            })
         }
     }
 
     /**
      * Same method as [RoomKeysRestClient.getRoomKey] except that it accepts nullable
-     * parameters and always returns a KeysBackupData object through the Callback
+     * parameters and always returns a KeysBackupData object through the Callback.
      */
     private suspend fun getKeys(sessionId: String?,
                                 roomId: String?,
@@ -801,19 +866,27 @@ internal class DefaultKeysBackupService @Inject constructor(
             // Get key for the room and for the session
             val data = getRoomSessionDataTask.execute(GetRoomSessionDataTask.Params(roomId, sessionId, version))
             // Convert to KeysBackupData
-            KeysBackupData(mutableMapOf(
-                    roomId to RoomKeysBackupData(mutableMapOf(
-                            sessionId to data
-                    ))
-            ))
+            KeysBackupData(
+                    mutableMapOf(
+                            roomId to RoomKeysBackupData(
+                                    mutableMapOf(
+                                            sessionId to data
+                                    )
+                            )
+                    )
+            )
         } else if (roomId != null) {
             // Get all keys for the room
-            val data = getRoomSessionsDataTask.execute(GetRoomSessionsDataTask.Params(roomId, version))
+            val data = withContext(coroutineDispatchers.io) {
+                getRoomSessionsDataTask.execute(GetRoomSessionsDataTask.Params(roomId, version))
+            }
             // Convert to KeysBackupData
             KeysBackupData(mutableMapOf(roomId to data))
         } else {
             // Get all keys
-            getSessionsDataTask.execute(GetSessionsDataTask.Params(version))
+            withContext(coroutineDispatchers.io) {
+                getSessionsDataTask.execute(GetSessionsDataTask.Params(version))
+            }
         }
     }
 
@@ -838,7 +911,7 @@ internal class DefaultKeysBackupService @Inject constructor(
     }
 
     /**
-     * Do a backup if there are new keys, with a delay
+     * Do a backup if there are new keys, with a delay.
      */
     fun maybeBackupKeys() {
         when {
@@ -1149,7 +1222,7 @@ internal class DefaultKeysBackupService @Inject constructor(
     }
 
     /**
-     * Update the DB with data fetch from the server
+     * Update the DB with data fetch from the server.
      */
     private fun onServerDataRetrieved(count: Int?, etag: String?) {
         cryptoStore.setKeysBackupData(KeysBackupDataEntity()
@@ -1178,7 +1251,7 @@ internal class DefaultKeysBackupService @Inject constructor(
     }
 
     /**
-     * Send a chunk of keys to backup
+     * Send a chunk of keys to backup.
      */
     @UiThread
     private fun backupKeys() {
@@ -1189,7 +1262,6 @@ internal class DefaultKeysBackupService @Inject constructor(
             Timber.v("backupKeys: Invalid configuration")
             backupAllGroupSessionsCallback?.onFailure(IllegalStateException("Invalid configuration"))
             resetBackupAllGroupSessionsListeners()
-
             return
         }
 
@@ -1326,7 +1398,8 @@ internal class DefaultKeysBackupService @Inject constructor(
                 "sender_key" to sessionData.senderKey,
                 "sender_claimed_keys" to sessionData.senderClaimedKeys,
                 "forwarding_curve25519_key_chain" to (sessionData.forwardingCurve25519KeyChain.orEmpty()),
-                "session_key" to sessionData.sessionKey)
+                "session_key" to sessionData.sessionKey
+        )
 
         val json = MoshiProvider.providesMoshi()
                 .adapter(Map::class.java)
@@ -1354,7 +1427,8 @@ internal class DefaultKeysBackupService @Inject constructor(
                 sessionData = mapOf(
                         "ciphertext" to encryptedSessionBackupData.mCipherText,
                         "mac" to encryptedSessionBackupData.mMac,
-                        "ephemeral" to encryptedSessionBackupData.mEphemeralKey)
+                        "ephemeral" to encryptedSessionBackupData.mEphemeralKey
+                )
         )
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPassword.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPassword.kt
index 4d5b38acbf18fabdd3d3f0537faae556933fe77a..d5bab3318094b6485167893b736f7ea2ad579aaa 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPassword.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPassword.kt
@@ -59,7 +59,7 @@ internal fun generatePrivateKeyWithPassword(password: String,
 }
 
 /**
- * Retrieve a private key from {password, salt, iterations}
+ * Retrieve a private key from {password, salt, iterations}.
  *
  * @param password the password used to generated the private key.
  * @param salt the salt.
@@ -143,7 +143,7 @@ internal fun deriveKey(password: String,
 }
 
 /**
- * Generate a 32 chars salt
+ * Generate a 32 chars salt.
  */
 private fun generateSalt(): String {
     val salt = buildString {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/api/RoomKeysApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/api/RoomKeysApi.kt
index 8464b33526fe4abaac5bcfe167c10b18a9f48257..ea23be59237de603f6c6ce4b649f4b709e3ef22f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/api/RoomKeysApi.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/api/RoomKeysApi.kt
@@ -50,7 +50,7 @@ internal interface RoomKeysApi {
     suspend fun createKeysBackupVersion(@Body createKeysBackupVersionBody: CreateKeysBackupVersionBody): KeysVersion
 
     /**
-     * Get the key backup last version
+     * Get the key backup last version.
      * If not supported by the server, an error is returned: {"errcode":"M_NOT_FOUND","error":"No backup found"}
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/version")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/CreateKeysBackupVersionBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/CreateKeysBackupVersionBody.kt
index a6bd8f8aaa564f24878ea04f1bd6aabe44e6caba..2d483893c09e460b6ff26e9a0b90dfd77c622db7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/CreateKeysBackupVersionBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/CreateKeysBackupVersionBody.kt
@@ -23,13 +23,13 @@ import org.matrix.android.sdk.api.util.JsonDict
 @JsonClass(generateAdapter = true)
 internal data class CreateKeysBackupVersionBody(
         /**
-         * The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
+         * The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined.
          */
         @Json(name = "algorithm")
         override val algorithm: String,
 
         /**
-         * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2"
+         * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2".
          * see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
          */
         @Json(name = "auth_data")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysAlgorithmAndData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysAlgorithmAndData.kt
index 898b357c51791b19f75be713db7675665c6b46cc..19581a686bb1e24add093cfe33335d23fa1ae82f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysAlgorithmAndData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/KeysAlgorithmAndData.kt
@@ -41,17 +41,17 @@ import org.matrix.android.sdk.internal.di.MoshiProvider
 internal interface KeysAlgorithmAndData {
 
     /**
-     * The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
+     * The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined.
      */
     val algorithm: String
 
     /**
-     * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
+     * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData].
      */
     val authData: JsonDict
 
     /**
-     * Facility method to convert authData to a MegolmBackupAuthData object
+     * Facility method to convert authData to a MegolmBackupAuthData object.
      */
     fun getAuthDataAsMegolmBackupAuthData(): MegolmBackupAuthData? {
         return MoshiProvider.providesMoshi()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/UpdateKeysBackupVersionBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/UpdateKeysBackupVersionBody.kt
index 3f2def84d556d244a063efb714d27f33ff5f3255..a4b8f811e46412ea85b5d4c611cba569965a729a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/UpdateKeysBackupVersionBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/model/rest/UpdateKeysBackupVersionBody.kt
@@ -29,7 +29,7 @@ internal data class UpdateKeysBackupVersionBody(
         override val algorithm: String,
 
         /**
-         * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2"
+         * algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2".
          * see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
          */
         @Json(name = "auth_data")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionDataTask.kt
index 7f1b03b9324a0ad8e898bd0827589e5d0420e9a3..f90522b03632c4ec8d3da19c7967dae14e5298a7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionDataTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionDataTask.kt
@@ -40,7 +40,8 @@ internal class DefaultDeleteRoomSessionDataTask @Inject constructor(
             roomKeysApi.deleteRoomSessionData(
                     params.roomId,
                     params.sessionId,
-                    params.version)
+                    params.version
+            )
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionsDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionsDataTask.kt
index 394cc861d625008d44c8a6e8ca19e1f928dda3ea..7db33e0c46b9cdf52be81f4972619940c8784961 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionsDataTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/DeleteRoomSessionsDataTask.kt
@@ -38,7 +38,8 @@ internal class DefaultDeleteRoomSessionsDataTask @Inject constructor(
         return executeRequest(globalErrorReceiver) {
             roomKeysApi.deleteRoomSessionsData(
                     params.roomId,
-                    params.version)
+                    params.version
+            )
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionDataTask.kt
index ff515ed80fa34df7256e639be9c4cdda94edde84..df8e6bfebfc5303884230da52d86b6db1dbde87f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionDataTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionDataTask.kt
@@ -41,7 +41,8 @@ internal class DefaultGetRoomSessionDataTask @Inject constructor(
             roomKeysApi.getRoomSessionData(
                     params.roomId,
                     params.sessionId,
-                    params.version)
+                    params.version
+            )
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionsDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionsDataTask.kt
index 1b4fe2d96622719d80b6becd3d489b749312c2f5..f9ea078ef2bc11f87133f60f92b434b9fcee6f03 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionsDataTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/GetRoomSessionsDataTask.kt
@@ -39,7 +39,8 @@ internal class DefaultGetRoomSessionsDataTask @Inject constructor(
         return executeRequest(globalErrorReceiver) {
             roomKeysApi.getRoomSessionsData(
                     params.roomId,
-                    params.version)
+                    params.version
+            )
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionDataTask.kt
index 180aaecf82000b020b7c67d78bfc69357ebeae5b..637c6ddeb70d28c847b9fb182f12f0dab187eca5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionDataTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionDataTask.kt
@@ -44,7 +44,8 @@ internal class DefaultStoreRoomSessionDataTask @Inject constructor(
                     params.roomId,
                     params.sessionId,
                     params.version,
-                    params.keyBackupData)
+                    params.keyBackupData
+            )
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionsDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionsDataTask.kt
index d1aa9d2eb03831701c3c71a0d5cdefa8814b24ba..09e52da7555b906259ad11bb078d098b3b2dc101 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionsDataTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreRoomSessionsDataTask.kt
@@ -42,7 +42,8 @@ internal class DefaultStoreRoomSessionsDataTask @Inject constructor(
             roomKeysApi.storeRoomSessionsData(
                     params.roomId,
                     params.version,
-                    params.roomKeysBackupData)
+                    params.roomKeysBackupData
+            )
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreSessionsDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreSessionsDataTask.kt
index 3dbeafe9dee2cb866e98c33b04e762fd5713119c..47f2578c4375bb9c6f2f88a55c8e0943b5d5b274 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreSessionsDataTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/tasks/StoreSessionsDataTask.kt
@@ -40,7 +40,8 @@ internal class DefaultStoreSessionsDataTask @Inject constructor(
         return executeRequest(globalErrorReceiver) {
             roomKeysApi.storeSessionsData(
                     params.version,
-                    params.keysBackupData)
+                    params.keysBackupData
+            )
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/util/Base58.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/util/Base58.kt
index 0e746f289b8c921a4876c1a1d1d2202dceb27bee..407e034acbdf80313eee9d9ec94329980f0305ec 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/util/Base58.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/util/Base58.kt
@@ -39,7 +39,7 @@ private const val ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqr
 private val BASE = BigInteger.valueOf(58)
 
 /**
- * Encode a byte array to a human readable string with base58 chars
+ * Encode a byte array to a human readable string with base58 chars.
  */
 internal fun base58encode(input: ByteArray): String {
     var bi = BigInteger(1, input)
@@ -62,7 +62,7 @@ internal fun base58encode(input: ByteArray): String {
 }
 
 /**
- * Decode a base58 String to a byte array
+ * Decode a base58 String to a byte array.
  */
 internal fun base58decode(input: String): ByteArray {
     var result = decodeToBigInteger(input).toByteArray()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt
index cff713bf8f72ed1f2e6d6edb7127f0beb1a65f7f..6bfa56ae8df7cfec01d60f6b474c091314f6fdd8 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt
@@ -36,13 +36,13 @@ internal data class MXKey(
         val value: String,
 
         /**
-         * signature user Id to [deviceid][signature]
+         * signature user Id to [deviceid][signature].
          */
         private val signatures: Map<String, Map<String, String>>,
 
         /**
          * We have to store the original json because it can contain other fields
-         * that we don't support yet but they would be needed to check signatures
+         * that we don't support yet but they would be needed to check signatures.
          */
         private val rawMap: JsonDict
 ) {
@@ -57,7 +57,7 @@ internal data class MXKey(
     }
 
     /**
-     * Returns a signature for an user Id and a signkey
+     * Returns a signature for an user Id and a signkey.
      *
      * @param userId  the user id
      * @param signkey the sign key
@@ -81,7 +81,7 @@ internal data class MXKey(
         // const val KEY_ED_25519_TYPE = "ed25519"
 
         /**
-         * Convert a map to a MXKey
+         * Convert a map to a MXKey.
          *
          * @param map the map to convert
          *
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXOlmSessionResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXOlmSessionResult.kt
index 671827799e273bae75e9e29a4d61e366047c613f..666ab2d678c8c4c3195605594c11bc07db8c50d3 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXOlmSessionResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXOlmSessionResult.kt
@@ -21,7 +21,7 @@ import java.io.Serializable
 
 internal data class MXOlmSessionResult(
         /**
-         * the device
+         * the device.
          */
         val deviceInfo: CryptoDeviceInfo,
         /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper.kt
index 45ffcc66064c2d831611410e375cfda52dfca10d..ecb29466800f20e430facdf4aa40798f9ced8f8c 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper.kt
@@ -60,7 +60,7 @@ internal class OlmInboundGroupSessionWrapper : Serializable {
         }
 
     /**
-     * Constructor
+     * Constructor.
      *
      * @param sessionKey the session key
      * @param isImported true if it is an imported session key
@@ -101,7 +101,7 @@ internal class OlmInboundGroupSessionWrapper : Serializable {
     }
 
     /**
-     * Export the inbound group session keys
+     * Export the inbound group session keys.
      *
      * @return the inbound group session as MegolmSessionData if the operation succeeds
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt
index 1f671aa896228c1f02d9aaf500b6f5801682b9e8..289c169d6d142ddfaee52badaed4f97f551c0ec4 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmInboundGroupSessionWrapper2.kt
@@ -57,7 +57,7 @@ internal class OlmInboundGroupSessionWrapper2 : Serializable {
         }
 
     /**
-     * Constructor
+     * Constructor.
      *
      * @param sessionKey the session key
      * @param isImported true if it is an imported session key
@@ -104,7 +104,7 @@ internal class OlmInboundGroupSessionWrapper2 : Serializable {
     }
 
     /**
-     * Export the inbound group session keys
+     * Export the inbound group session keys.
      * @param index the index to export. If null, the first known index will be used
      *
      * @return the inbound group session as MegolmSessionData if the operation succeeds
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmSessionWrapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmSessionWrapper.kt
index d7ce553f39aebfbba1f97fbb4161edc6987bcb31..a1e58ead0cb325e9f221b3a24e97a5f65ca55e54 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmSessionWrapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/OlmSessionWrapper.kt
@@ -20,7 +20,7 @@ import kotlinx.coroutines.sync.Mutex
 import org.matrix.olm.OlmSession
 
 /**
- * Encapsulate a OlmSession and a last received message Timestamp
+ * Encapsulate a OlmSession and a last received message Timestamp.
  */
 internal data class OlmSessionWrapper(
         // The associated olm session.
@@ -32,7 +32,7 @@ internal data class OlmSessionWrapper(
 ) {
 
     /**
-     * Notify that a message has been received on this olm session so that it updates `lastReceivedMessageTs`
+     * Notify that a message has been received on this olm session so that it updates `lastReceivedMessageTs`.
      */
     fun onMessageReceived(currentTimeMillis: Long) {
         lastReceivedMessageTs = currentTimeMillis
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DeleteDeviceParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DeleteDeviceParams.kt
index f636ab890d92224cfa236e658cf281fe3401d5a8..c26c6107c4eeb53fa346e4b969d13123d787ec01 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DeleteDeviceParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DeleteDeviceParams.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * This class provides the parameter to delete a device
+ * This class provides the parameter to delete a device.
  */
 @JsonClass(generateAdapter = true)
 internal data class DeleteDeviceParams(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyChangesResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyChangesResponse.kt
index f0ed77a1e335d82faab9e682522c7fe05c59aae7..5d432eca8cf362293f380d3701941a3d905e239b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyChangesResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyChangesResponse.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * This class describes the key changes response
+ * This class describes the key changes response.
  */
 @JsonClass(generateAdapter = true)
 internal data class KeyChangesResponse(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationAccept.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationAccept.kt
index 7a5773bf24d02b25de8d01aec4b9a30b0a2abfd1..9fdeda01c9db3093be37c53f78eae27458df7711 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationAccept.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationAccept.kt
@@ -35,25 +35,25 @@ internal data class KeyVerificationAccept(
         override val transactionId: String? = null,
 
         /**
-         * The key agreement protocol that Bob’s device has selected to use, out of the list proposed by Alice’s device
+         * The key agreement protocol that Bob’s device has selected to use, out of the list proposed by Alice’s device.
          */
         @Json(name = "key_agreement_protocol")
         override val keyAgreementProtocol: String? = null,
 
         /**
-         * The hash algorithm that Bob’s device has selected to use, out of the list proposed by Alice’s device
+         * The hash algorithm that Bob’s device has selected to use, out of the list proposed by Alice’s device.
          */
         @Json(name = "hash")
         override val hash: String? = null,
 
         /**
-         * The message authentication code that Bob’s device has selected to use, out of the list proposed by Alice’s device
+         * The message authentication code that Bob’s device has selected to use, out of the list proposed by Alice’s device.
          */
         @Json(name = "message_authentication_code")
         override val messageAuthenticationCode: String? = null,
 
         /**
-         * An array of short authentication string methods that Bob’s client (and Bob) understands.  Must be a subset of the list proposed by Alice’s device
+         * An array of short authentication string methods that Bob’s client (and Bob) understands.  Must be a subset of the list proposed by Alice’s device.
          */
         @Json(name = "short_authentication_string")
         override val shortAuthenticationStrings: List<String>? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationCancel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationCancel.kt
index 90272bf0e4bfafae0c50235603d7428972b18f61..2858ef3eed8b8ee12de9110cda089dd7ea5256d7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationCancel.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationCancel.kt
@@ -27,18 +27,18 @@ import org.matrix.android.sdk.internal.crypto.verification.VerificationInfoCance
 @JsonClass(generateAdapter = true)
 internal data class KeyVerificationCancel(
         /**
-         * the transaction ID of the verification to cancel
+         * the transaction ID of the verification to cancel.
          */
         @Json(name = "transaction_id")
         override val transactionId: String? = null,
 
         /**
-         * machine-readable reason for cancelling, see #CancelCode
+         * machine-readable reason for cancelling, see #CancelCode.
          */
         override val code: String? = null,
 
         /**
-         * human-readable reason for cancelling.  This should only be used if the receiving client does not understand the code given.
+         * human-readable reason for cancelling. This should only be used if the receiving client does not understand the code given.
          */
         override val reason: String? = null
 ) : SendToDeviceObject, VerificationInfoCancel {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationKey.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationKey.kt
index 19d8c32ddf7c9f2df333d198f69f68397dfdda30..a833148b9d7e4a271e8899b31d48a4bfb8af959e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationKey.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationKey.kt
@@ -27,12 +27,12 @@ import org.matrix.android.sdk.internal.crypto.verification.VerificationInfoKeyFa
 @JsonClass(generateAdapter = true)
 internal data class KeyVerificationKey(
         /**
-         * the ID of the transaction that the message is part of
+         * The ID of the transaction that the message is part of.
          */
         @Json(name = "transaction_id") override val transactionId: String? = null,
 
         /**
-         * The device’s ephemeral public key, as an unpadded base64 string
+         * The device’s ephemeral public key, as an unpadded base64 string.
          */
         @Json(name = "key") override val key: String? = null
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeysQueryBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeysQueryBody.kt
index 4f98be9da3d7891e0bb333a339458d392198dbed..dc570820f2848e7b09fb0e0839a854eb47c87827 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeysQueryBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeysQueryBody.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * This class represents the body to /keys/query
+ * This class represents the body to /keys/query.
  */
 @JsonClass(generateAdapter = true)
 internal data class KeysQueryBody(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeysUploadResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeysUploadResponse.kt
index 3d0ea8677f03394e980df1890bb4cd9aac104892..c445f55ba78753994bd11845a46f4b64d44dfcd3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeysUploadResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeysUploadResponse.kt
@@ -31,7 +31,7 @@ internal data class KeysUploadResponse(
         val oneTimeKeyCounts: Map<String, Int>? = null
 ) {
     /**
-     * Helper methods to extract information from 'oneTimeKeyCounts'
+     * Helper methods to extract information from 'oneTimeKeyCounts'.
      *
      * @param algorithm the expected algorithm
      * @return the time key counts
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/RestKeyInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/RestKeyInfo.kt
index 66247d07d1e02c4b135909a58a860bc7b9bbdd02..cdcbe5ffe208c9d806777075b8c19775f4ce7840 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/RestKeyInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/RestKeyInfo.kt
@@ -23,7 +23,7 @@ import org.matrix.android.sdk.internal.crypto.model.CryptoInfoMapper
 @JsonClass(generateAdapter = true)
 internal data class RestKeyInfo(
         /**
-         * The user who owns the key
+         * The user who owns the key.
          */
         @Json(name = "user_id")
         val userId: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/ShareRequestCancellation.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/ShareRequestCancellation.kt
index a96534fc3af1ac4f72b49297f4ac6d3c83f78c1e..ea9b451ed66da5d0200dfc5b03dfe32564ead20e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/ShareRequestCancellation.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/ShareRequestCancellation.kt
@@ -21,7 +21,7 @@ import org.matrix.android.sdk.api.session.crypto.model.GossipingToDeviceObject
 import org.matrix.android.sdk.api.session.crypto.model.GossipingToDeviceObject.Companion.ACTION_SHARE_CANCELLATION
 
 /**
- * Class representing a room key request cancellation content
+ * Class representing a room key request cancellation content.
  */
 @JsonClass(generateAdapter = true)
 internal data class ShareRequestCancellation(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/SignatureUploadResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/SignatureUploadResponse.kt
index fb92b67fc47a9317badd12d009fb096470916019..f89426d91bbf84a38f06683462ea11700d8619d6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/SignatureUploadResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/SignatureUploadResponse.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Upload Signature response
+ * Upload Signature response.
  */
 @JsonClass(generateAdapter = true)
 internal data class SignatureUploadResponse(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/UploadSignatureQueryBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/UploadSignatureQueryBuilder.kt
index dd0ce47cd36162ffd15e2a1d1d4f12026e69a8b2..1c1e223bc8411408254567e09a2b9e722fd2744c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/UploadSignatureQueryBuilder.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/UploadSignatureQueryBuilder.kt
@@ -21,7 +21,7 @@ import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
 import org.matrix.android.sdk.internal.crypto.model.toRest
 
 /**
- * Helper class to build CryptoApi#uploadSignatures params
+ * Helper class to build CryptoApi#uploadSignatures params.
  */
 internal data class UploadSignatureQueryBuilder(
         private val deviceInfoList: MutableList<CryptoDeviceInfo> = mutableListOf(),
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/repository/WarnOnUnknownDeviceRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/repository/WarnOnUnknownDeviceRepository.kt
index deec8b1b3c00f86cc7e94f61fa666f1f1b3d3477..d699950e4fa889239da3c1230368f84e6cf6455b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/repository/WarnOnUnknownDeviceRepository.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/repository/WarnOnUnknownDeviceRepository.kt
@@ -22,7 +22,7 @@ import javax.inject.Inject
 @SessionScope
 internal class WarnOnUnknownDeviceRepository @Inject constructor() {
 
-    // TODO: set it back to true by default. Need UI
+    // TODO set it back to true by default. Need UI
     // Warn the user if some new devices are detected while encrypting a message.
     private var warnOnUnknownDevices = false
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt
index 8c877593e74424183ce18b0e8510d198a36b688a..1ded9c6c7e32b83f11870cd6cca18470746ec0ee 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt
@@ -40,7 +40,7 @@ import org.matrix.android.sdk.api.session.securestorage.SsssKeySpec
 import org.matrix.android.sdk.api.session.securestorage.SsssPassphrase
 import org.matrix.android.sdk.api.util.fromBase64
 import org.matrix.android.sdk.api.util.toBase64NoPadding
-import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager
+import org.matrix.android.sdk.internal.crypto.SecretShareManager
 import org.matrix.android.sdk.internal.crypto.keysbackup.generatePrivateKeyWithPassword
 import org.matrix.android.sdk.internal.crypto.tools.HkdfSha256
 import org.matrix.android.sdk.internal.crypto.tools.withOlmDecryption
@@ -57,7 +57,7 @@ import kotlin.experimental.and
 internal class DefaultSharedSecretStorageService @Inject constructor(
         @UserId private val userId: String,
         private val accountDataService: SessionAccountDataService,
-        private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
+        private val secretShareManager: SecretShareManager,
         private val coroutineDispatchers: MatrixCoroutineDispatchers,
         private val cryptoCoroutineScope: CoroutineScope
 ) : SharedSecretStorageService {
@@ -213,7 +213,8 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
                 secretKey.privateKey,
                 ByteArray(32) { 0.toByte() },
                 secretName.toByteArray(),
-                64)
+                64
+        )
 
         // The first 32 bytes are used as the AES key, and the next 32 bytes are used as the MAC key
         val aesKey = pseudoRandomKey.copyOfRange(0, 32)
@@ -255,7 +256,8 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
                 secretKey.privateKey,
                 ByteArray(32) { 0.toByte() },
                 secretName.toByteArray(),
-                64)
+                64
+        )
 
         // The first 32 bytes are used as the AES key, and the next 32 bytes are used as the MAC key
         val aesKey = pseudoRandomKey.copyOfRange(0, 32)
@@ -378,10 +380,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
         return IntegrityResult.Success(keyInfo.content.passphrase != null)
     }
 
-    override fun requestSecret(name: String, myOtherDeviceId: String) {
-        outgoingGossipingRequestManager.sendSecretShareRequest(
-                name,
-                mapOf(userId to listOf(myOtherDeviceId))
-        )
+    override suspend fun requestSecret(name: String, myOtherDeviceId: String) {
+        secretShareManager.requestSecretTo(myOtherDeviceId, name)
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt
index 8bedb78808f0e793f93df89f7069fae7a538768d..480009dbce0c45c56a29916eba6229df1abbbc68 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt
@@ -19,23 +19,22 @@ package org.matrix.android.sdk.internal.crypto.store
 import androidx.lifecycle.LiveData
 import androidx.paging.PagedList
 import org.matrix.android.sdk.api.session.crypto.NewSessionListener
+import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest
+import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState
 import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
 import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
 import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo
 import org.matrix.android.sdk.api.session.crypto.keysbackup.SavedKeyBackupKeyInfo
+import org.matrix.android.sdk.api.session.crypto.model.AuditTrail
 import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
 import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
-import org.matrix.android.sdk.api.session.crypto.model.GossipingRequestState
-import org.matrix.android.sdk.api.session.crypto.model.IncomingRoomKeyRequest
 import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingGossipingRequestState
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingRoomKeyRequest
 import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
+import org.matrix.android.sdk.api.session.crypto.model.TrailType
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
+import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
 import org.matrix.android.sdk.api.util.Optional
-import org.matrix.android.sdk.internal.crypto.IncomingShareRequestCommon
-import org.matrix.android.sdk.internal.crypto.OutgoingSecretRequest
 import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
 import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
 import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper
@@ -44,7 +43,7 @@ import org.matrix.olm.OlmAccount
 import org.matrix.olm.OlmOutboundGroupSession
 
 /**
- * the crypto data store
+ * The crypto data store.
  */
 internal interface IMXCryptoStore {
 
@@ -82,6 +81,15 @@ internal interface IMXCryptoStore {
      */
     fun setGlobalBlacklistUnverifiedDevices(block: Boolean)
 
+    /**
+     * Enable or disable key gossiping.
+     * Default is true.
+     * If set to false this device won't send key_request nor will accept key forwarded
+     */
+    fun enableKeyGossiping(enable: Boolean)
+
+    fun isKeyGossipingEnabled(): Boolean
+
     /**
      * Provides the rooms ids list in which the messages are not encrypted for the unverified devices.
      *
@@ -97,24 +105,24 @@ internal interface IMXCryptoStore {
     fun setRoomsListBlacklistUnverifiedDevices(roomIds: List<String>)
 
     /**
-     * Get the current keys backup version
+     * Get the current keys backup version.
      */
     fun getKeyBackupVersion(): String?
 
     /**
-     * Set the current keys backup version
+     * Set the current keys backup version.
      *
      * @param keyBackupVersion the keys backup version or null to delete it
      */
     fun setKeyBackupVersion(keyBackupVersion: String?)
 
     /**
-     * Get the current keys backup local data
+     * Get the current keys backup local data.
      */
     fun getKeysBackupData(): KeysBackupDataEntity?
 
     /**
-     * Set the keys backup local data
+     * Set the keys backup local data.
      *
      * @param keysBackupData the keys backup local data, or null to erase data
      */
@@ -125,18 +133,6 @@ internal interface IMXCryptoStore {
      */
     fun getDeviceTrackingStatuses(): Map<String, Int>
 
-    /**
-     * @return the pending IncomingRoomKeyRequest requests
-     */
-    fun getPendingIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest>
-
-    fun getPendingIncomingGossipingRequests(): List<IncomingShareRequestCommon>
-
-    fun storeIncomingGossipingRequest(request: IncomingShareRequestCommon, ageLocalTS: Long?)
-
-    fun storeIncomingGossipingRequests(requests: List<IncomingShareRequestCommon>)
-//    fun getPendingIncomingSecretShareRequests(): List<IncomingSecretShareRequest>
-
     /**
      * Indicate if the store contains data for the passed account.
      *
@@ -150,12 +146,12 @@ internal interface IMXCryptoStore {
     fun deleteStore()
 
     /**
-     * open any existing crypto store
+     * open any existing crypto store.
      */
     fun open()
 
     /**
-     * Close the store
+     * Close the store.
      */
     fun close()
 
@@ -243,10 +239,10 @@ internal interface IMXCryptoStore {
     fun getRoomAlgorithm(roomId: String): String?
 
     /**
-     * This is a bit different than isRoomEncrypted
-     * A room is encrypted when there is a m.room.encryption state event in the room (malformed/invalid or not)
-     * But the crypto layer has additional guaranty to ensure that encryption would never been reverted
-     * It's defensive coding out of precaution (if ever state is reset)
+     * This is a bit different than isRoomEncrypted.
+     * A room is encrypted when there is a m.room.encryption state event in the room (malformed/invalid or not).
+     * But the crypto layer has additional guaranty to ensure that encryption would never been reverted.
+     * It's defensive coding out of precaution (if ever state is reset).
      */
     fun roomWasOnceEncrypted(roomId: String): Boolean
 
@@ -282,7 +278,7 @@ internal interface IMXCryptoStore {
     fun getDeviceSession(sessionId: String, deviceKey: String): OlmSessionWrapper?
 
     /**
-     * Retrieve the last used sessionId, regarding `lastReceivedMessageTs`, or null if no session exist
+     * Retrieve the last used sessionId, regarding `lastReceivedMessageTs`, or null if no session exist.
      *
      * @param deviceKey the public key of the other device.
      * @return last used sessionId, or null if not found
@@ -306,17 +302,17 @@ internal interface IMXCryptoStore {
     fun getInboundGroupSession(sessionId: String, senderKey: String): OlmInboundGroupSessionWrapper2?
 
     /**
-     * Get the current outbound group session for this encrypted room
+     * Get the current outbound group session for this encrypted room.
      */
     fun getCurrentOutboundGroupSessionForRoom(roomId: String): OutboundGroupSessionWrapper?
 
     /**
-     * Get the current outbound group session for this encrypted room
+     * Get the current outbound group session for this encrypted room.
      */
     fun storeCurrentOutboundGroupSessionForRoom(roomId: String, outboundGroupSession: OlmOutboundGroupSession?)
 
     /**
-     * Remove an inbound group session
+     * Remove an inbound group session.
      *
      * @param sessionId the session identifier.
      * @param senderKey the base64-encoded curve25519 key of the sender.
@@ -356,7 +352,7 @@ internal interface IMXCryptoStore {
     fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int
 
     /**
-     * Save the device statuses
+     * Save the device statuses.
      *
      * @param deviceTrackingStatuses the device tracking statuses
      */
@@ -372,12 +368,14 @@ internal interface IMXCryptoStore {
     fun getDeviceTrackingStatus(userId: String, defaultValue: Int): Int
 
     /**
-     * Look for an existing outgoing room key request, and if none is found, return null
+     * Look for an existing outgoing room key request, and if none is found, return null.
      *
      * @param requestBody the request body
      * @return an OutgoingRoomKeyRequest instance or null
      */
-    fun getOutgoingRoomKeyRequest(requestBody: RoomKeyRequestBody): OutgoingRoomKeyRequest?
+    fun getOutgoingRoomKeyRequest(requestBody: RoomKeyRequestBody): OutgoingKeyRequest?
+    fun getOutgoingRoomKeyRequest(requestId: String): OutgoingKeyRequest?
+    fun getOutgoingRoomKeyRequest(roomId: String, sessionId: String, algorithm: String, senderKey: String): List<OutgoingKeyRequest>
 
     /**
      * Look for an existing outgoing room key request, and if none is found, add a new one.
@@ -385,39 +383,59 @@ internal interface IMXCryptoStore {
      * @param request the request
      * @return either the same instance as passed in, or the existing one.
      */
-    fun getOrAddOutgoingRoomKeyRequest(requestBody: RoomKeyRequestBody, recipients: Map<String, List<String>>): OutgoingRoomKeyRequest?
-
-    fun getOrAddOutgoingSecretShareRequest(secretName: String, recipients: Map<String, List<String>>): OutgoingSecretRequest?
-
-    fun saveGossipingEvent(event: Event) = saveGossipingEvents(listOf(event))
-
-    fun saveGossipingEvents(events: List<Event>)
-
-    fun updateGossipingRequestState(request: IncomingShareRequestCommon, state: GossipingRequestState) {
-        updateGossipingRequestState(
-                requestUserId = request.userId,
-                requestDeviceId = request.deviceId,
-                requestId = request.requestId,
-                state = state
-        )
-    }
-
-    fun updateGossipingRequestState(requestUserId: String?,
-                                    requestDeviceId: String?,
-                                    requestId: String?,
-                                    state: GossipingRequestState)
-
-    /**
-     * Search an IncomingRoomKeyRequest
-     *
-     * @param userId    the user id
-     * @param deviceId  the device id
-     * @param requestId the request id
-     * @return an IncomingRoomKeyRequest if it exists, else null
-     */
-    fun getIncomingRoomKeyRequest(userId: String, deviceId: String, requestId: String): IncomingRoomKeyRequest?
-
-    fun updateOutgoingGossipingRequestState(requestId: String, state: OutgoingGossipingRequestState)
+    fun getOrAddOutgoingRoomKeyRequest(requestBody: RoomKeyRequestBody, recipients: Map<String, List<String>>, fromIndex: Int): OutgoingKeyRequest
+    fun updateOutgoingRoomKeyRequestState(requestId: String, newState: OutgoingRoomKeyRequestState)
+    fun updateOutgoingRoomKeyRequiredIndex(requestId: String, newIndex: Int)
+    fun updateOutgoingRoomKeyReply(
+            roomId: String,
+            sessionId: String,
+            algorithm: String,
+            senderKey: String,
+            fromDevice: String?,
+            event: Event)
+
+    fun deleteOutgoingRoomKeyRequest(requestId: String)
+    fun deleteOutgoingRoomKeyRequestInState(state: OutgoingRoomKeyRequestState)
+
+    fun saveIncomingKeyRequestAuditTrail(
+            requestId: String,
+            roomId: String,
+            sessionId: String,
+            senderKey: String,
+            algorithm: String,
+            fromUser: String,
+            fromDevice: String
+    )
+
+    fun saveWithheldAuditTrail(
+            roomId: String,
+            sessionId: String,
+            senderKey: String,
+            algorithm: String,
+            code: WithHeldCode,
+            userId: String,
+            deviceId: String
+    )
+
+    fun saveForwardKeyAuditTrail(
+            roomId: String,
+            sessionId: String,
+            senderKey: String,
+            algorithm: String,
+            userId: String,
+            deviceId: String,
+            chainIndex: Long?
+    )
+
+    fun saveIncomingForwardKeyAuditTrail(
+            roomId: String,
+            sessionId: String,
+            senderKey: String,
+            algorithm: String,
+            userId: String,
+            deviceId: String,
+            chainIndex: Long?
+    )
 
     fun addNewSessionListener(listener: NewSessionListener)
 
@@ -428,7 +446,7 @@ internal interface IMXCryptoStore {
     // =============================================
 
     /**
-     * Gets the current crosssigning info
+     * Gets the current crosssigning info.
      */
     fun getMyCrossSigningInfo(): MXCrossSigningInfo?
 
@@ -477,17 +495,15 @@ internal interface IMXCryptoStore {
     fun getSharedWithInfo(roomId: String?, sessionId: String): MXUsersDevicesMap<Int>
     // Dev tools
 
-    fun getOutgoingRoomKeyRequests(): List<OutgoingRoomKeyRequest>
-    fun getOutgoingRoomKeyRequestsPaged(): LiveData<PagedList<OutgoingRoomKeyRequest>>
-    fun getOutgoingSecretKeyRequests(): List<OutgoingSecretRequest>
-    fun getOutgoingSecretRequest(secretName: String): OutgoingSecretRequest?
-    fun getIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest>
-    fun getIncomingRoomKeyRequestsPaged(): LiveData<PagedList<IncomingRoomKeyRequest>>
-    fun getGossipingEventsTrail(): LiveData<PagedList<Event>>
-    fun getGossipingEvents(): List<Event>
+    fun getOutgoingRoomKeyRequests(): List<OutgoingKeyRequest>
+    fun getOutgoingRoomKeyRequestsPaged(): LiveData<PagedList<OutgoingKeyRequest>>
+    fun getGossipingEventsTrail(): LiveData<PagedList<AuditTrail>>
+    fun <T> getGossipingEventsTrail(type: TrailType, mapper: ((AuditTrail) -> T)): LiveData<PagedList<T>>
+    fun getGossipingEvents(): List<AuditTrail>
 
     fun setDeviceKeysUploaded(uploaded: Boolean)
     fun areDeviceKeysUploaded(): Boolean
     fun tidyUpDataBase()
     fun logDbUsageInfo()
+    fun getOutgoingRoomKeyRequests(inStates: Set<OutgoingRoomKeyRequestState>): List<OutgoingKeyRequest>
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt
index b841e9c6e58a2843322d40b5168b68a8331f2a86..2d66ce1488f125cc44235f3d7eee64da86d5c7ea 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt
@@ -26,7 +26,7 @@ import java.util.zip.GZIPInputStream
 import java.util.zip.GZIPOutputStream
 
 /**
- * Get realm, invoke the action, close realm, and return the result of the action
+ * Get realm, invoke the action, close realm, and return the result of the action.
  */
 internal fun <T> doWithRealm(realmConfiguration: RealmConfiguration, action: (Realm) -> T): T {
     return Realm.getInstance(realmConfiguration).use { realm ->
@@ -35,7 +35,7 @@ internal fun <T> doWithRealm(realmConfiguration: RealmConfiguration, action: (Re
 }
 
 /**
- * Get realm, do the query, copy from realm, close realm, and return the copied result
+ * Get realm, do the query, copy from realm, close realm, and return the copied result.
  */
 internal fun <T : RealmObject> doRealmQueryAndCopy(realmConfiguration: RealmConfiguration, action: (Realm) -> T?): T? {
     return Realm.getInstance(realmConfiguration).use { realm ->
@@ -44,7 +44,7 @@ internal fun <T : RealmObject> doRealmQueryAndCopy(realmConfiguration: RealmConf
 }
 
 /**
- * Get realm, do the list query, copy from realm, close realm, and return the copied result
+ * Get realm, do the list query, copy from realm, close realm, and return the copied result.
  */
 internal fun <T : RealmObject> doRealmQueryAndCopyList(realmConfiguration: RealmConfiguration, action: (Realm) -> Iterable<T>): Iterable<T> {
     return Realm.getInstance(realmConfiguration).use { realm ->
@@ -53,7 +53,7 @@ internal fun <T : RealmObject> doRealmQueryAndCopyList(realmConfiguration: Realm
 }
 
 /**
- * Get realm instance, invoke the action in a transaction and close realm
+ * Get realm instance, invoke the action in a transaction and close realm.
  */
 internal fun doRealmTransaction(realmConfiguration: RealmConfiguration, action: (Realm) -> Unit) {
     Realm.getInstance(realmConfiguration).use { realm ->
@@ -68,7 +68,7 @@ internal fun doRealmTransactionAsync(realmConfiguration: RealmConfiguration, act
 }
 
 /**
- * Serialize any Serializable object, zip it and convert to Base64 String
+ * Serialize any Serializable object, zip it and convert to Base64 String.
  */
 internal fun serializeForRealm(o: Any?): String? {
     if (o == null) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt
index a509315e7af28f04a9f07c2ed585aae6546659b5..533ab70bba3ce0095825a10deae8f83d7df07d06 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt
@@ -24,37 +24,40 @@ import com.zhuinden.monarchy.Monarchy
 import io.realm.Realm
 import io.realm.RealmConfiguration
 import io.realm.Sort
+import io.realm.kotlin.createObject
 import io.realm.kotlin.where
 import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
 import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.logger.LoggerTag
 import org.matrix.android.sdk.api.session.crypto.NewSessionListener
+import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest
+import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState
 import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
 import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
 import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo
 import org.matrix.android.sdk.api.session.crypto.keysbackup.SavedKeyBackupKeyInfo
+import org.matrix.android.sdk.api.session.crypto.model.AuditTrail
 import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
 import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
-import org.matrix.android.sdk.api.session.crypto.model.GossipingRequestState
-import org.matrix.android.sdk.api.session.crypto.model.IncomingRoomKeyRequest
-import org.matrix.android.sdk.api.session.crypto.model.IncomingSecretShareRequest
+import org.matrix.android.sdk.api.session.crypto.model.ForwardInfo
+import org.matrix.android.sdk.api.session.crypto.model.IncomingKeyRequestInfo
 import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingGossipingRequestState
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingRoomKeyRequest
 import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
+import org.matrix.android.sdk.api.session.crypto.model.TrailType
+import org.matrix.android.sdk.api.session.crypto.model.WithheldInfo
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
-import org.matrix.android.sdk.api.session.room.send.SendState
+import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
 import org.matrix.android.sdk.api.util.Optional
 import org.matrix.android.sdk.api.util.toOptional
-import org.matrix.android.sdk.internal.crypto.GossipRequestType
-import org.matrix.android.sdk.internal.crypto.IncomingShareRequestCommon
-import org.matrix.android.sdk.internal.crypto.OutgoingSecretRequest
 import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
 import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
 import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
+import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntity
+import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntityFields
+import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailMapper
 import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields
 import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMapper
@@ -63,10 +66,6 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
 import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFields
-import org.matrix.android.sdk.internal.crypto.store.db.model.GossipingEventEntity
-import org.matrix.android.sdk.internal.crypto.store.db.model.GossipingEventEntityFields
-import org.matrix.android.sdk.internal.crypto.store.db.model.IncomingGossipingRequestEntity
-import org.matrix.android.sdk.internal.crypto.store.db.model.IncomingGossipingRequestEntityFields
 import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity
@@ -74,8 +73,8 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSess
 import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntityFields
 import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntity
-import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingGossipingRequestEntity
-import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingGossipingRequestEntityFields
+import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntity
+import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields
 import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
@@ -89,7 +88,6 @@ import org.matrix.android.sdk.internal.crypto.store.db.query.get
 import org.matrix.android.sdk.internal.crypto.store.db.query.getById
 import org.matrix.android.sdk.internal.crypto.store.db.query.getOrCreate
 import org.matrix.android.sdk.internal.crypto.util.RequestIdHelper
-import org.matrix.android.sdk.internal.database.mapper.ContentMapper
 import org.matrix.android.sdk.internal.database.tools.RealmDebugTools
 import org.matrix.android.sdk.internal.di.CryptoDatabase
 import org.matrix.android.sdk.internal.di.DeviceId
@@ -106,6 +104,8 @@ import java.util.concurrent.Executors
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 
+private val loggerTag = LoggerTag("RealmCryptoStore", LoggerTag.CRYPTO)
+
 @SessionScope
 internal class RealmCryptoStore @Inject constructor(
         @CryptoDatabase private val realmConfiguration: RealmConfiguration,
@@ -233,7 +233,7 @@ internal class RealmCryptoStore @Inject constructor(
     }
 
     /**
-     * Olm account access should be synchronized
+     * Olm account access should be synchronized.
      */
     override fun <T> doWithOlmAccount(block: (OlmAccount) -> T): T {
         return olmAccount!!.let { olmAccount ->
@@ -273,12 +273,13 @@ internal class RealmCryptoStore @Inject constructor(
     }
 
     override fun deviceWithIdentityKey(identityKey: String): CryptoDeviceInfo? {
-        return doWithRealm(realmConfiguration) {
-            it.where<DeviceInfoEntity>()
-                    .equalTo(DeviceInfoEntityFields.IDENTITY_KEY, identityKey)
-                    .findFirst()
-                    ?.let { deviceInfo ->
-                        CryptoMapper.mapToModel(deviceInfo)
+        return doWithRealm(realmConfiguration) { realm ->
+            realm.where<DeviceInfoEntity>()
+                    .contains(DeviceInfoEntityFields.KEYS_MAP_JSON, identityKey)
+                    .findAll()
+                    .mapNotNull { CryptoMapper.mapToModel(it) }
+                    .firstOrNull {
+                        it.identityKey() == identityKey
                     }
         }
     }
@@ -743,14 +744,23 @@ internal class RealmCryptoStore @Inject constructor(
                 if (sessionIdentifier != null) {
                     val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionIdentifier, session.senderKey)
 
-                    val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply {
-                        primaryKey = key
-                        sessionId = sessionIdentifier
-                        senderKey = session.senderKey
-                        putInboundGroupSession(session)
-                    }
+                    val existing = realm.where<OlmInboundGroupSessionEntity>()
+                            .equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
+                            .findFirst()
+
+                    if (existing != null) {
+                        // we want to keep the existing backup status
+                        existing.putInboundGroupSession(session)
+                    } else {
+                        val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply {
+                            primaryKey = key
+                            sessionId = sessionIdentifier
+                            senderKey = session.senderKey
+                            putInboundGroupSession(session)
+                        }
 
-                    realm.insertOrUpdate(realmOlmInboundGroupSession)
+                        realm.insertOrUpdate(realmOlmInboundGroupSession)
+                    }
                 }
             }
         }
@@ -805,7 +815,7 @@ internal class RealmCryptoStore @Inject constructor(
 
     /**
      * Note: the result will be only use to export all the keys and not to use the OlmInboundGroupSessionWrapper2,
-     * so there is no need to use or update `inboundGroupSessionToRelease` for native memory management
+     * so there is no need to use or update `inboundGroupSessionToRelease` for native memory management.
      */
     override fun getInboundGroupSessions(): List<OlmInboundGroupSessionWrapper2> {
         return doWithRealm(realmConfiguration) {
@@ -879,18 +889,33 @@ internal class RealmCryptoStore @Inject constructor(
             return
         }
 
-        doRealmTransaction(realmConfiguration) {
+        doRealmTransaction(realmConfiguration) { realm ->
             olmInboundGroupSessionWrappers.forEach { olmInboundGroupSessionWrapper ->
                 try {
+                    val sessionIdentifier = olmInboundGroupSessionWrapper.olmInboundGroupSession?.sessionIdentifier()
                     val key = OlmInboundGroupSessionEntity.createPrimaryKey(
-                            olmInboundGroupSessionWrapper.olmInboundGroupSession?.sessionIdentifier(),
+                            sessionIdentifier,
                             olmInboundGroupSessionWrapper.senderKey
                     )
 
-                    it.where<OlmInboundGroupSessionEntity>()
+                    val existing = realm.where<OlmInboundGroupSessionEntity>()
                             .equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
                             .findFirst()
-                            ?.backedUp = true
+
+                    if (existing != null) {
+                        existing.backedUp = true
+                    } else {
+                        // ... might be in cache but not yet persisted, create a record to persist backedup state
+                        val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply {
+                            primaryKey = key
+                            sessionId = sessionIdentifier
+                            senderKey = olmInboundGroupSessionWrapper.senderKey
+                            putInboundGroupSession(olmInboundGroupSessionWrapper)
+                            backedUp = true
+                        }
+
+                        realm.insertOrUpdate(realmOlmInboundGroupSession)
+                    }
                 } catch (e: OlmException) {
                     Timber.e(e, "OlmException")
                 }
@@ -929,6 +954,18 @@ internal class RealmCryptoStore @Inject constructor(
         }
     }
 
+    override fun enableKeyGossiping(enable: Boolean) {
+        doRealmTransaction(realmConfiguration) {
+            it.where<CryptoMetadataEntity>().findFirst()?.globalEnableKeyGossiping = enable
+        }
+    }
+
+    override fun isKeyGossipingEnabled(): Boolean {
+        return doWithRealm(realmConfiguration) {
+            it.where<CryptoMetadataEntity>().findFirst()?.globalEnableKeyGossiping
+        } ?: true
+    }
+
     override fun getGlobalBlacklistUnverifiedDevices(): Boolean {
         return doWithRealm(realmConfiguration) {
             it.where<CryptoMetadataEntity>().findFirst()?.globalBlacklistUnverifiedDevices
@@ -1010,12 +1047,13 @@ internal class RealmCryptoStore @Inject constructor(
                 ?: defaultValue
     }
 
-    override fun getOutgoingRoomKeyRequest(requestBody: RoomKeyRequestBody): OutgoingRoomKeyRequest? {
+    override fun getOutgoingRoomKeyRequest(requestBody: RoomKeyRequestBody): OutgoingKeyRequest? {
         return monarchy.fetchAllCopiedSync { realm ->
-            realm.where<OutgoingGossipingRequestEntity>()
-                    .equalTo(OutgoingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name)
-        }.mapNotNull {
-            it.toOutgoingGossipingRequest() as? OutgoingRoomKeyRequest
+            realm.where<OutgoingKeyRequestEntity>()
+                    .equalTo(OutgoingKeyRequestEntityFields.ROOM_ID, requestBody.roomId)
+                    .equalTo(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID, requestBody.sessionId)
+        }.map {
+            it.toOutgoingKeyRequest()
         }.firstOrNull {
             it.requestBody?.algorithm == requestBody.algorithm &&
                     it.requestBody?.roomId == requestBody.roomId &&
@@ -1024,41 +1062,37 @@ internal class RealmCryptoStore @Inject constructor(
         }
     }
 
-    override fun getOutgoingSecretRequest(secretName: String): OutgoingSecretRequest? {
+    override fun getOutgoingRoomKeyRequest(requestId: String): OutgoingKeyRequest? {
         return monarchy.fetchAllCopiedSync { realm ->
-            realm.where<OutgoingGossipingRequestEntity>()
-                    .equalTo(OutgoingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.SECRET.name)
-                    .equalTo(OutgoingGossipingRequestEntityFields.REQUESTED_INFO_STR, secretName)
-        }.mapNotNull {
-            it.toOutgoingGossipingRequest() as? OutgoingSecretRequest
+            realm.where<OutgoingKeyRequestEntity>()
+                    .equalTo(OutgoingKeyRequestEntityFields.REQUEST_ID, requestId)
+        }.map {
+            it.toOutgoingKeyRequest()
         }.firstOrNull()
     }
 
-    override fun getIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest> {
+    override fun getOutgoingRoomKeyRequest(roomId: String, sessionId: String, algorithm: String, senderKey: String): List<OutgoingKeyRequest> {
+        // TODO this annoying we have to load all
         return monarchy.fetchAllCopiedSync { realm ->
-            realm.where<IncomingGossipingRequestEntity>()
-                    .equalTo(IncomingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name)
-        }.mapNotNull {
-            it.toIncomingGossipingRequest() as? IncomingRoomKeyRequest
+            realm.where<OutgoingKeyRequestEntity>()
+                    .equalTo(OutgoingKeyRequestEntityFields.ROOM_ID, roomId)
+                    .equalTo(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID, sessionId)
+        }.map {
+            it.toOutgoingKeyRequest()
+        }.filter {
+            it.requestBody?.algorithm == algorithm &&
+                    it.requestBody?.senderKey == senderKey
         }
     }
 
-    override fun getIncomingRoomKeyRequestsPaged(): LiveData<PagedList<IncomingRoomKeyRequest>> {
+    override fun getGossipingEventsTrail(): LiveData<PagedList<AuditTrail>> {
         val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
-            realm.where<IncomingGossipingRequestEntity>()
-                    .equalTo(IncomingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name)
-                    .sort(IncomingGossipingRequestEntityFields.LOCAL_CREATION_TIMESTAMP, Sort.DESCENDING)
+            realm.where<AuditTrailEntity>().sort(AuditTrailEntityFields.AGE_LOCAL_TS, Sort.DESCENDING)
         }
         val dataSourceFactory = realmDataSourceFactory.map {
-            it.toIncomingGossipingRequest() as? IncomingRoomKeyRequest
-                    ?: IncomingRoomKeyRequest(
-                            requestBody = null,
-                            deviceId = "",
-                            userId = "",
-                            requestId = "",
-                            state = GossipingRequestState.NONE,
-                            localCreationTimestamp = 0
-                    )
+            AuditTrailMapper.map(it)
+            // mm we can't map not null...
+                    ?: createUnknownTrail()
         }
         return monarchy.findAllPagedWithChanges(
                 realmDataSourceFactory,
@@ -1073,12 +1107,33 @@ internal class RealmCryptoStore @Inject constructor(
         )
     }
 
-    override fun getGossipingEventsTrail(): LiveData<PagedList<Event>> {
+    private fun createUnknownTrail() = AuditTrail(
+            clock.epochMillis(),
+            TrailType.Unknown,
+            IncomingKeyRequestInfo(
+                    "",
+                    "",
+                    "",
+                    "",
+                    "",
+                    "",
+                    "",
+            )
+    )
+
+    override fun <T> getGossipingEventsTrail(type: TrailType, mapper: ((AuditTrail) -> T)): LiveData<PagedList<T>> {
         val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
-            realm.where<GossipingEventEntity>().sort(GossipingEventEntityFields.AGE_LOCAL_TS, Sort.DESCENDING)
+            realm.where<AuditTrailEntity>()
+                    .equalTo(AuditTrailEntityFields.TYPE, type.name)
+                    .sort(AuditTrailEntityFields.AGE_LOCAL_TS, Sort.DESCENDING)
         }
-        val dataSourceFactory = realmDataSourceFactory.map { it.toModel() }
-        val trail = monarchy.findAllPagedWithChanges(
+        val dataSourceFactory = realmDataSourceFactory.map { entity ->
+            (AuditTrailMapper.map(entity)
+            // mm we can't map not null...
+                    ?: createUnknownTrail()
+                    ).let { mapper.invoke(it) }
+        }
+        return monarchy.findAllPagedWithChanges(
                 realmDataSourceFactory,
                 LivePagedListBuilder(
                         dataSourceFactory,
@@ -1089,28 +1144,36 @@ internal class RealmCryptoStore @Inject constructor(
                                 .build()
                 )
         )
-        return trail
     }
 
-    override fun getGossipingEvents(): List<Event> {
+    override fun getGossipingEvents(): List<AuditTrail> {
         return monarchy.fetchAllCopiedSync { realm ->
-            realm.where<GossipingEventEntity>()
-        }.map {
-            it.toModel()
+            realm.where<AuditTrailEntity>()
+        }.mapNotNull {
+            AuditTrailMapper.map(it)
         }
     }
 
-    override fun getOrAddOutgoingRoomKeyRequest(requestBody: RoomKeyRequestBody, recipients: Map<String, List<String>>): OutgoingRoomKeyRequest? {
+    override fun getOrAddOutgoingRoomKeyRequest(requestBody: RoomKeyRequestBody,
+                                                recipients: Map<String, List<String>>,
+                                                fromIndex: Int): OutgoingKeyRequest {
         // Insert the request and return the one passed in parameter
-        var request: OutgoingRoomKeyRequest? = null
+        lateinit var request: OutgoingKeyRequest
         doRealmTransaction(realmConfiguration) { realm ->
 
-            val existing = realm.where<OutgoingGossipingRequestEntity>()
-                    .equalTo(OutgoingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name)
+            val existing = realm.where<OutgoingKeyRequestEntity>()
+                    .equalTo(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID, requestBody.sessionId)
+                    .equalTo(OutgoingKeyRequestEntityFields.ROOM_ID, requestBody.roomId)
                     .findAll()
-                    .mapNotNull {
-                        it.toOutgoingGossipingRequest() as? OutgoingRoomKeyRequest
-                    }.firstOrNull {
+                    .map {
+                        it.toOutgoingKeyRequest()
+                    }.also {
+                        if (it.size > 1) {
+                            // there should be one or zero but not more, worth warning
+                            Timber.tag(loggerTag.value).w("There should not be more than one active key request per session")
+                        }
+                    }
+                    .firstOrNull {
                         it.requestBody?.algorithm == requestBody.algorithm &&
                                 it.requestBody?.sessionId == requestBody.sessionId &&
                                 it.requestBody?.senderKey == requestBody.senderKey &&
@@ -1118,13 +1181,14 @@ internal class RealmCryptoStore @Inject constructor(
                     }
 
             if (existing == null) {
-                request = realm.createObject(OutgoingGossipingRequestEntity::class.java).apply {
+                request = realm.createObject(OutgoingKeyRequestEntity::class.java).apply {
                     this.requestId = RequestIdHelper.createUniqueRequestId()
                     this.setRecipients(recipients)
-                    this.requestState = OutgoingGossipingRequestState.UNSENT
-                    this.type = GossipRequestType.KEY
-                    this.requestedInfoStr = requestBody.toJson()
-                }.toOutgoingGossipingRequest() as? OutgoingRoomKeyRequest
+                    this.requestedIndex = fromIndex
+                    this.requestState = OutgoingRoomKeyRequestState.UNSENT
+                    this.setRequestBody(requestBody)
+                    this.creationTimeStamp = clock.epochMillis()
+                }.toOutgoingKeyRequest()
             } else {
                 request = existing
             }
@@ -1132,285 +1196,176 @@ internal class RealmCryptoStore @Inject constructor(
         return request
     }
 
-    override fun getOrAddOutgoingSecretShareRequest(secretName: String, recipients: Map<String, List<String>>): OutgoingSecretRequest? {
-        var request: OutgoingSecretRequest? = null
-
-        // Insert the request and return the one passed in parameter
+    override fun updateOutgoingRoomKeyRequestState(requestId: String, newState: OutgoingRoomKeyRequestState) {
         doRealmTransaction(realmConfiguration) { realm ->
-            val existing = realm.where<OutgoingGossipingRequestEntity>()
-                    .equalTo(OutgoingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.SECRET.name)
-                    .equalTo(OutgoingGossipingRequestEntityFields.REQUESTED_INFO_STR, secretName)
-                    .findAll()
-                    .mapNotNull {
-                        it.toOutgoingGossipingRequest() as? OutgoingSecretRequest
-                    }.firstOrNull()
-            if (existing == null) {
-                request = realm.createObject(OutgoingGossipingRequestEntity::class.java).apply {
-                    this.type = GossipRequestType.SECRET
-                    setRecipients(recipients)
-                    this.requestState = OutgoingGossipingRequestState.UNSENT
-                    this.requestId = RequestIdHelper.createUniqueRequestId()
-                    this.requestedInfoStr = secretName
-                }.toOutgoingGossipingRequest() as? OutgoingSecretRequest
-            } else {
-                request = existing
-            }
-        }
-
-        return request
-    }
-
-    override fun saveGossipingEvents(events: List<Event>) {
-        monarchy.writeAsync { realm ->
-            val now = clock.epochMillis()
-            events.forEach { event ->
-                val ageLocalTs = event.unsignedData?.age?.let { now - it } ?: now
-                val entity = GossipingEventEntity(
-                        type = event.type,
-                        sender = event.senderId,
-                        ageLocalTs = ageLocalTs,
-                        content = ContentMapper.map(event.content)
-                ).apply {
-                    sendState = SendState.SYNCED
-                    decryptionResultJson = MoshiProvider.providesMoshi().adapter(OlmDecryptionResult::class.java).toJson(event.mxDecryptionResult)
-                    decryptionErrorCode = event.mCryptoError?.name
-                }
-                realm.insertOrUpdate(entity)
-            }
+            realm.where<OutgoingKeyRequestEntity>()
+                    .equalTo(OutgoingKeyRequestEntityFields.REQUEST_ID, requestId)
+                    .findFirst()?.apply {
+                        this.requestState = newState
+                        if (newState == OutgoingRoomKeyRequestState.UNSENT) {
+                            // clear the old replies
+                            this.replies.deleteAllFromRealm()
+                        }
+                    }
         }
     }
 
-//    override fun getOutgoingRoomKeyRequestByState(states: Set<ShareRequestState>): OutgoingRoomKeyRequest? {
-//        val statesIndex = states.map { it.ordinal }.toTypedArray()
-//        return doRealmQueryAndCopy(realmConfiguration) { realm ->
-//            realm.where<GossipingEventEntity>()
-//                    .equalTo(GossipingEventEntityFields.SENDER, credentials.userId)
-//                    .findAll()
-//                    .filter {entity ->
-//                        states.any { it == entity.requestState}
-//                    }
-//        }.mapNotNull {
-//            ContentMapper.map(it.content)?.toModel<OutgoingSecretRequest>()
-//        }
-//                ?.toOutgoingRoomKeyRequest()
-//    }
-//
-//    override fun getOutgoingSecretShareRequestByState(states: Set<ShareRequestState>): OutgoingSecretRequest? {
-//        val statesIndex = states.map { it.ordinal }.toTypedArray()
-//        return doRealmQueryAndCopy(realmConfiguration) {
-//            it.where<OutgoingSecretRequestEntity>()
-//                    .`in`(OutgoingSecretRequestEntityFields.STATE, statesIndex)
-//                    .findFirst()
-//        }
-//                ?.toOutgoingSecretRequest()
-//    }
-
-//    override fun updateOutgoingRoomKeyRequest(request: OutgoingRoomKeyRequest) {
-//        doRealmTransaction(realmConfiguration) {
-//            val obj = OutgoingRoomKeyRequestEntity().apply {
-//                requestId = request.requestId
-//                cancellationTxnId = request.cancellationTxnId
-//                state = request.state.ordinal
-//                putRecipients(request.recipients)
-//                putRequestBody(request.requestBody)
-//            }
-//
-//            it.insertOrUpdate(obj)
-//        }
-//    }
-
-//    override fun deleteOutgoingRoomKeyRequest(transactionId: String) {
-//        doRealmTransaction(realmConfiguration) {
-//            it.where<OutgoingRoomKeyRequestEntity>()
-//                    .equalTo(OutgoingRoomKeyRequestEntityFields.REQUEST_ID, transactionId)
-//                    .findFirst()
-//                    ?.deleteFromRealm()
-//        }
-//    }
-
-//    override fun storeIncomingRoomKeyRequest(incomingRoomKeyRequest: IncomingRoomKeyRequest?) {
-//        if (incomingRoomKeyRequest == null) {
-//            return
-//        }
-//
-//        doRealmTransaction(realmConfiguration) {
-//            // Delete any previous store request with the same parameters
-//            it.where<IncomingRoomKeyRequestEntity>()
-//                    .equalTo(IncomingRoomKeyRequestEntityFields.USER_ID, incomingRoomKeyRequest.userId)
-//                    .equalTo(IncomingRoomKeyRequestEntityFields.DEVICE_ID, incomingRoomKeyRequest.deviceId)
-//                    .equalTo(IncomingRoomKeyRequestEntityFields.REQUEST_ID, incomingRoomKeyRequest.requestId)
-//                    .findAll()
-//                    .deleteAllFromRealm()
-//
-//            // Then store it
-//            it.createObject(IncomingRoomKeyRequestEntity::class.java).apply {
-//                userId = incomingRoomKeyRequest.userId
-//                deviceId = incomingRoomKeyRequest.deviceId
-//                requestId = incomingRoomKeyRequest.requestId
-//                putRequestBody(incomingRoomKeyRequest.requestBody)
-//            }
-//        }
-//    }
-
-//    override fun deleteIncomingRoomKeyRequest(incomingRoomKeyRequest: IncomingShareRequestCommon) {
-//        doRealmTransaction(realmConfiguration) {
-//            it.where<GossipingEventEntity>()
-//                    .equalTo(GossipingEventEntityFields.TYPE, EventType.ROOM_KEY_REQUEST)
-//                    .notEqualTo(GossipingEventEntityFields.SENDER, credentials.userId)
-//                    .findAll()
-//                    .filter {
-//                        ContentMapper.map(it.content).toModel<IncomingRoomKeyRequest>()?.let {
-//
-//                        }
-//                    }
-// //                    .equalTo(IncomingRoomKeyRequestEntityFields.USER_ID, incomingRoomKeyRequest.userId)
-// //                    .equalTo(IncomingRoomKeyRequestEntityFields.DEVICE_ID, incomingRoomKeyRequest.deviceId)
-// //                    .equalTo(IncomingRoomKeyRequestEntityFields.REQUEST_ID, incomingRoomKeyRequest.requestId)
-// //                    .findAll()
-// //                    .deleteAllFromRealm()
-//        }
-//    }
-
-    override fun updateGossipingRequestState(requestUserId: String?,
-                                             requestDeviceId: String?,
-                                             requestId: String?,
-                                             state: GossipingRequestState) {
+    override fun updateOutgoingRoomKeyRequiredIndex(requestId: String, newIndex: Int) {
         doRealmTransaction(realmConfiguration) { realm ->
-            realm.where<IncomingGossipingRequestEntity>()
-                    .equalTo(IncomingGossipingRequestEntityFields.OTHER_USER_ID, requestUserId)
-                    .equalTo(IncomingGossipingRequestEntityFields.OTHER_DEVICE_ID, requestDeviceId)
-                    .equalTo(IncomingGossipingRequestEntityFields.REQUEST_ID, requestId)
-                    .findAll().forEach {
-                        it.requestState = state
+            realm.where<OutgoingKeyRequestEntity>()
+                    .equalTo(OutgoingKeyRequestEntityFields.REQUEST_ID, requestId)
+                    .findFirst()?.apply {
+                        this.requestedIndex = newIndex
                     }
         }
     }
 
-    override fun updateOutgoingGossipingRequestState(requestId: String, state: OutgoingGossipingRequestState) {
+    override fun updateOutgoingRoomKeyReply(roomId: String,
+                                            sessionId: String,
+                                            algorithm: String,
+                                            senderKey: String,
+                                            fromDevice: String?,
+                                            event: Event) {
         doRealmTransaction(realmConfiguration) { realm ->
-            realm.where<OutgoingGossipingRequestEntity>()
-                    .equalTo(OutgoingGossipingRequestEntityFields.REQUEST_ID, requestId)
-                    .findAll().forEach {
-                        it.requestState = state
+            realm.where<OutgoingKeyRequestEntity>()
+                    .equalTo(OutgoingKeyRequestEntityFields.ROOM_ID, roomId)
+                    .equalTo(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID, sessionId)
+                    .findAll().firstOrNull { entity ->
+                        entity.toOutgoingKeyRequest().let {
+                            it.requestBody?.senderKey == senderKey &&
+                                    it.requestBody?.algorithm == algorithm
+                        }
+                    }?.apply {
+                        event.senderId?.let { addReply(it, fromDevice, event) }
                     }
         }
     }
 
-    override fun getIncomingRoomKeyRequest(userId: String, deviceId: String, requestId: String): IncomingRoomKeyRequest? {
-        return doWithRealm(realmConfiguration) { realm ->
-            realm.where<IncomingGossipingRequestEntity>()
-                    .equalTo(IncomingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name)
-                    .equalTo(IncomingGossipingRequestEntityFields.OTHER_DEVICE_ID, deviceId)
-                    .equalTo(IncomingGossipingRequestEntityFields.OTHER_USER_ID, userId)
-                    .findAll()
-                    .mapNotNull { entity ->
-                        entity.toIncomingGossipingRequest() as? IncomingRoomKeyRequest
-                    }
-                    .firstOrNull()
+    override fun deleteOutgoingRoomKeyRequest(requestId: String) {
+        doRealmTransaction(realmConfiguration) { realm ->
+            realm.where<OutgoingKeyRequestEntity>()
+                    .equalTo(OutgoingKeyRequestEntityFields.REQUEST_ID, requestId)
+                    .findFirst()?.deleteOnCascade()
         }
     }
 
-    override fun getPendingIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest> {
-        return doWithRealm(realmConfiguration) {
-            it.where<IncomingGossipingRequestEntity>()
-                    .equalTo(IncomingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name)
-                    .equalTo(IncomingGossipingRequestEntityFields.REQUEST_STATE_STR, GossipingRequestState.PENDING.name)
+    override fun deleteOutgoingRoomKeyRequestInState(state: OutgoingRoomKeyRequestState) {
+        doRealmTransaction(realmConfiguration) { realm ->
+            realm.where<OutgoingKeyRequestEntity>()
+                    .equalTo(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR, state.name)
                     .findAll()
-                    .map { entity ->
-                        IncomingRoomKeyRequest(
-                                userId = entity.otherUserId,
-                                deviceId = entity.otherDeviceId,
-                                requestId = entity.requestId,
-                                requestBody = entity.getRequestedKeyInfo(),
-                                localCreationTimestamp = entity.localCreationTimestamp
-                        )
-                    }
+                    // I delete like this because I want to cascade delete replies?
+                    .onEach { it.deleteOnCascade() }
         }
     }
 
-    override fun getPendingIncomingGossipingRequests(): List<IncomingShareRequestCommon> {
-        return doWithRealm(realmConfiguration) {
-            it.where<IncomingGossipingRequestEntity>()
-                    .equalTo(IncomingGossipingRequestEntityFields.REQUEST_STATE_STR, GossipingRequestState.PENDING.name)
-                    .findAll()
-                    .mapNotNull { entity ->
-                        when (entity.type) {
-                            GossipRequestType.KEY -> {
-                                IncomingRoomKeyRequest(
-                                        userId = entity.otherUserId,
-                                        deviceId = entity.otherDeviceId,
-                                        requestId = entity.requestId,
-                                        requestBody = entity.getRequestedKeyInfo(),
-                                        localCreationTimestamp = entity.localCreationTimestamp
-                                )
-                            }
-                            GossipRequestType.SECRET -> {
-                                IncomingSecretShareRequest(
-                                        userId = entity.otherUserId,
-                                        deviceId = entity.otherDeviceId,
-                                        requestId = entity.requestId,
-                                        secretName = entity.getRequestedSecretName(),
-                                        localCreationTimestamp = entity.localCreationTimestamp
-                                )
-                            }
-                        }
-                    }
+    override fun saveIncomingKeyRequestAuditTrail(
+            requestId: String,
+            roomId: String,
+            sessionId: String,
+            senderKey: String,
+            algorithm: String,
+            fromUser: String,
+            fromDevice: String) {
+        monarchy.writeAsync { realm ->
+            val now = clock.epochMillis()
+            realm.createObject<AuditTrailEntity>().apply {
+                this.ageLocalTs = now
+                this.type = TrailType.IncomingKeyRequest.name
+                val info = IncomingKeyRequestInfo(
+                        roomId = roomId,
+                        sessionId = sessionId,
+                        senderKey = senderKey,
+                        alg = algorithm,
+                        userId = fromUser,
+                        deviceId = fromDevice,
+                        requestId = requestId
+                )
+                MoshiProvider.providesMoshi().adapter(IncomingKeyRequestInfo::class.java).toJson(info)?.let {
+                    this.contentJson = it
+                }
+            }
         }
     }
 
-    override fun storeIncomingGossipingRequest(request: IncomingShareRequestCommon, ageLocalTS: Long?) {
-        doRealmTransactionAsync(realmConfiguration) { realm ->
-
-            // After a clear cache, we might have a
-
-            realm.createObject(IncomingGossipingRequestEntity::class.java).let {
-                it.otherDeviceId = request.deviceId
-                it.otherUserId = request.userId
-                it.requestId = request.requestId ?: ""
-                it.requestState = GossipingRequestState.PENDING
-                it.localCreationTimestamp = ageLocalTS ?: clock.epochMillis()
-                if (request is IncomingSecretShareRequest) {
-                    it.type = GossipRequestType.SECRET
-                    it.requestedInfoStr = request.secretName
-                } else if (request is IncomingRoomKeyRequest) {
-                    it.type = GossipRequestType.KEY
-                    it.requestedInfoStr = request.requestBody?.toJson()
+    override fun saveWithheldAuditTrail(roomId: String,
+                                        sessionId: String,
+                                        senderKey: String,
+                                        algorithm: String,
+                                        code: WithHeldCode,
+                                        userId: String,
+                                        deviceId: String) {
+        monarchy.writeAsync { realm ->
+            val now = clock.epochMillis()
+            realm.createObject<AuditTrailEntity>().apply {
+                this.ageLocalTs = now
+                this.type = TrailType.OutgoingKeyWithheld.name
+                val info = WithheldInfo(
+                        roomId = roomId,
+                        sessionId = sessionId,
+                        senderKey = senderKey,
+                        alg = algorithm,
+                        code = code,
+                        userId = userId,
+                        deviceId = deviceId
+                )
+                MoshiProvider.providesMoshi().adapter(WithheldInfo::class.java).toJson(info)?.let {
+                    this.contentJson = it
                 }
             }
         }
     }
 
-    override fun storeIncomingGossipingRequests(requests: List<IncomingShareRequestCommon>) {
-        doRealmTransactionAsync(realmConfiguration) { realm ->
-            requests.forEach { request ->
-                // After a clear cache, we might have a
-                realm.createObject(IncomingGossipingRequestEntity::class.java).let {
-                    it.otherDeviceId = request.deviceId
-                    it.otherUserId = request.userId
-                    it.requestId = request.requestId ?: ""
-                    it.requestState = GossipingRequestState.PENDING
-                    it.localCreationTimestamp = request.localCreationTimestamp ?: clock.epochMillis()
-                    if (request is IncomingSecretShareRequest) {
-                        it.type = GossipRequestType.SECRET
-                        it.requestedInfoStr = request.secretName
-                    } else if (request is IncomingRoomKeyRequest) {
-                        it.type = GossipRequestType.KEY
-                        it.requestedInfoStr = request.requestBody?.toJson()
-                    }
+    override fun saveForwardKeyAuditTrail(roomId: String,
+                                          sessionId: String,
+                                          senderKey: String,
+                                          algorithm: String,
+                                          userId: String,
+                                          deviceId: String,
+                                          chainIndex: Long?) {
+        saveForwardKeyTrail(roomId, sessionId, senderKey, algorithm, userId, deviceId, chainIndex, false)
+    }
+
+    override fun saveIncomingForwardKeyAuditTrail(roomId: String,
+                                                  sessionId: String,
+                                                  senderKey: String,
+                                                  algorithm: String,
+                                                  userId: String,
+                                                  deviceId: String,
+                                                  chainIndex: Long?) {
+        saveForwardKeyTrail(roomId, sessionId, senderKey, algorithm, userId, deviceId, chainIndex, true)
+    }
+
+    private fun saveForwardKeyTrail(roomId: String,
+                                    sessionId: String,
+                                    senderKey: String,
+                                    algorithm: String,
+                                    userId: String,
+                                    deviceId: String,
+                                    chainIndex: Long?,
+                                    incoming: Boolean
+    ) {
+        monarchy.writeAsync { realm ->
+            val now = clock.epochMillis()
+            realm.createObject<AuditTrailEntity>().apply {
+                this.ageLocalTs = now
+                this.type = if (incoming) TrailType.IncomingKeyForward.name else TrailType.OutgoingKeyForward.name
+                val info = ForwardInfo(
+                        roomId = roomId,
+                        sessionId = sessionId,
+                        senderKey = senderKey,
+                        alg = algorithm,
+                        userId = userId,
+                        deviceId = deviceId,
+                        chainIndex = chainIndex
+                )
+                MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).toJson(info)?.let {
+                    this.contentJson = it
                 }
             }
         }
     }
 
-//    override fun getPendingIncomingSecretShareRequests(): List<IncomingSecretShareRequest> {
-//        return doRealmQueryAndCopyList(realmConfiguration) {
-//            it.where<GossipingEventEntity>()
-//                    .findAll()
-//        }.map {
-//            it.toIncomingSecretShareRequest()
-//        }
-//    }
-
     /* ==========================================================================================
      * Cross Signing
      * ========================================================================================== */
@@ -1513,37 +1468,34 @@ internal class RealmCryptoStore @Inject constructor(
         }
     }
 
-    override fun getOutgoingRoomKeyRequests(): List<OutgoingRoomKeyRequest> {
+    override fun getOutgoingRoomKeyRequests(): List<OutgoingKeyRequest> {
         return monarchy.fetchAllMappedSync({ realm ->
             realm
-                    .where(OutgoingGossipingRequestEntity::class.java)
-                    .equalTo(OutgoingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name)
+                    .where(OutgoingKeyRequestEntity::class.java)
         }, { entity ->
-            entity.toOutgoingGossipingRequest() as? OutgoingRoomKeyRequest
+            entity.toOutgoingKeyRequest()
         })
                 .filterNotNull()
     }
 
-    override fun getOutgoingSecretKeyRequests(): List<OutgoingSecretRequest> {
+    override fun getOutgoingRoomKeyRequests(inStates: Set<OutgoingRoomKeyRequestState>): List<OutgoingKeyRequest> {
         return monarchy.fetchAllMappedSync({ realm ->
             realm
-                    .where(OutgoingGossipingRequestEntity::class.java)
-                    .equalTo(OutgoingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.SECRET.name)
+                    .where(OutgoingKeyRequestEntity::class.java)
+                    .`in`(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR, inStates.map { it.name }.toTypedArray())
         }, { entity ->
-            entity.toOutgoingGossipingRequest() as? OutgoingSecretRequest
+            entity.toOutgoingKeyRequest()
         })
                 .filterNotNull()
     }
 
-    override fun getOutgoingRoomKeyRequestsPaged(): LiveData<PagedList<OutgoingRoomKeyRequest>> {
+    override fun getOutgoingRoomKeyRequestsPaged(): LiveData<PagedList<OutgoingKeyRequest>> {
         val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
             realm
-                    .where(OutgoingGossipingRequestEntity::class.java)
-                    .equalTo(OutgoingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name)
+                    .where(OutgoingKeyRequestEntity::class.java)
         }
         val dataSourceFactory = realmDataSourceFactory.map {
-            it.toOutgoingGossipingRequest() as? OutgoingRoomKeyRequest
-                    ?: OutgoingRoomKeyRequest(requestBody = null, requestId = "?", recipients = emptyMap(), state = OutgoingGossipingRequestState.CANCELLED)
+            it.toOutgoingKeyRequest()
         }
         val trail = monarchy.findAllPagedWithChanges(
                 realmDataSourceFactory,
@@ -1715,33 +1667,27 @@ internal class RealmCryptoStore @Inject constructor(
     }
 
     /**
-     * Some entries in the DB can get a bit out of control with time
-     * So we need to tidy up a bit
+     * Some entries in the DB can get a bit out of control with time.
+     * So we need to tidy up a bit.
      */
     override fun tidyUpDataBase() {
         val prevWeekTs = clock.epochMillis() - 7 * 24 * 60 * 60 * 1_000
         doRealmTransaction(realmConfiguration) { realm ->
 
-            // Only keep one week history
-            realm.where<IncomingGossipingRequestEntity>()
-                    .lessThan(IncomingGossipingRequestEntityFields.LOCAL_CREATION_TIMESTAMP, prevWeekTs)
+            // Clean the old ones?
+            realm.where<OutgoingKeyRequestEntity>()
+                    .lessThan(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, prevWeekTs)
                     .findAll()
-                    .also { Timber.i("## Crypto Clean up ${it.size} IncomingGossipingRequestEntity") }
+                    .also { Timber.i("## Crypto Clean up ${it.size} OutgoingKeyRequestEntity") }
                     .deleteAllFromRealm()
 
-            // Clean the cancelled ones?
-            realm.where<OutgoingGossipingRequestEntity>()
-                    .equalTo(OutgoingGossipingRequestEntityFields.REQUEST_STATE_STR, OutgoingGossipingRequestState.CANCELLED.name)
-                    .equalTo(OutgoingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name)
-                    .findAll()
-                    .also { Timber.i("## Crypto Clean up ${it.size} OutgoingGossipingRequestEntity") }
-                    .deleteAllFromRealm()
+            // Only keep one month history
 
-            // Only keep one week history
-            realm.where<GossipingEventEntity>()
-                    .lessThan(GossipingEventEntityFields.AGE_LOCAL_TS, prevWeekTs)
+            val prevMonthTs = clock.epochMillis() - 4 * 7 * 24 * 60 * 60 * 1_000L
+            realm.where<AuditTrailEntity>()
+                    .lessThan(AuditTrailEntityFields.AGE_LOCAL_TS, prevMonthTs)
                     .findAll()
-                    .also { Timber.i("## Crypto Clean up ${it.size} GossipingEventEntityFields") }
+                    .also { Timber.i("## Crypto Clean up ${it.size} AuditTrailEntity") }
                     .deleteAllFromRealm()
 
             // Can we do something for WithHeldSessionEntity?
@@ -1749,7 +1695,7 @@ internal class RealmCryptoStore @Inject constructor(
     }
 
     /**
-     * Prints out database info
+     * Prints out database info.
      */
     override fun logDbUsageInfo() {
         RealmDebugTools(realmConfiguration).logInfo("Crypto")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt
index 32f24c5d2e7897c92f5017315ee6ada4d7e50cb2..02c2a27decd9ae64f27246599e66d233ecf0724b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreMigration.kt
@@ -33,6 +33,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo
 import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo013
 import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo014
 import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo015
+import org.matrix.android.sdk.internal.crypto.store.db.migration.MigrateCryptoTo016
 import org.matrix.android.sdk.internal.util.time.Clock
 import timber.log.Timber
 import javax.inject.Inject
@@ -41,8 +42,8 @@ internal class RealmCryptoStoreMigration @Inject constructor(
         private val clock: Clock,
 ) : RealmMigration {
     /**
-     * Forces all RealmCryptoStoreMigration instances to be equal
-     * Avoids Realm throwing when multiple instances of the migration are set
+     * Forces all RealmCryptoStoreMigration instances to be equal.
+     * Avoids Realm throwing when multiple instances of the migration are set.
      */
     override fun equals(other: Any?) = other is RealmCryptoStoreMigration
     override fun hashCode() = 5000
@@ -50,7 +51,7 @@ internal class RealmCryptoStoreMigration @Inject constructor(
     // 0, 1, 2: legacy Riot-Android
     // 3: migrate to RiotX schema
     // 4, 5, 6, 7, 8, 9: migrations from RiotX (which was previously 1, 2, 3, 4, 5, 6)
-    val schemaVersion = 15L
+    val schemaVersion = 16L
 
     override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
         Timber.d("Migrating Realm Crypto from $oldVersion to $newVersion")
@@ -70,5 +71,6 @@ internal class RealmCryptoStoreMigration @Inject constructor(
         if (oldVersion < 13) MigrateCryptoTo013(realm).perform()
         if (oldVersion < 14) MigrateCryptoTo014(realm).perform()
         if (oldVersion < 15) MigrateCryptoTo015(realm).perform()
+        if (oldVersion < 16) MigrateCryptoTo016(realm).perform()
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreModule.kt
index a2f2f8e97ae65ecb8785c38607fd97364595cc25..6696cf8281d02939f9849f6e58fd1314060c221a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStoreModule.kt
@@ -17,28 +17,29 @@
 package org.matrix.android.sdk.internal.crypto.store.db
 
 import io.realm.annotations.RealmModule
+import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntity
-import org.matrix.android.sdk.internal.crypto.store.db.model.GossipingEventEntity
-import org.matrix.android.sdk.internal.crypto.store.db.model.IncomingGossipingRequestEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.KeyInfoEntity
+import org.matrix.android.sdk.internal.crypto.store.db.model.KeyRequestReplyEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.MyDeviceLastSeenInfoEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.OlmInboundGroupSessionEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.OlmSessionEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.OutboundGroupSessionInfoEntity
-import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingGossipingRequestEntity
+import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntity
 
 /**
- * Realm module for Crypto store classes
+ * Realm module for Crypto store classes.
  */
-@RealmModule(library = true,
+@RealmModule(
+        library = true,
         classes = [
             CryptoMetadataEntity::class,
             CryptoRoomEntity::class,
@@ -50,12 +51,13 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEnti
             KeyInfoEntity::class,
             CrossSigningInfoEntity::class,
             TrustLevelEntity::class,
-            GossipingEventEntity::class,
-            IncomingGossipingRequestEntity::class,
-            OutgoingGossipingRequestEntity::class,
+            AuditTrailEntity::class,
+            OutgoingKeyRequestEntity::class,
+            KeyRequestReplyEntity::class,
             MyDeviceLastSeenInfoEntity::class,
             WithHeldSessionEntity::class,
             SharedSessionEntity::class,
             OutboundGroupSessionInfoEntity::class
-        ])
+        ]
+)
 internal class RealmCryptoStoreModule
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/CrossSigningKeysMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/CrossSigningKeysMapper.kt
index 5e4b9b96da8ac3739606c62883b084d9818cad9e..8b7bf9c26b29183e2a93a61617572f11e035296a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/CrossSigningKeysMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/mapper/CrossSigningKeysMapper.kt
@@ -27,11 +27,13 @@ import javax.inject.Inject
 
 internal class CrossSigningKeysMapper @Inject constructor(moshi: Moshi) {
 
-    private val signaturesAdapter = moshi.adapter<Map<String, Map<String, String>>>(Types.newParameterizedType(
-            Map::class.java,
-            String::class.java,
-            Any::class.java
-    ))
+    private val signaturesAdapter = moshi.adapter<Map<String, Map<String, String>>>(
+            Types.newParameterizedType(
+                    Map::class.java,
+                    String::class.java,
+                    Any::class.java
+            )
+    )
 
     fun update(keyInfo: KeyInfoEntity, cryptoCrossSigningKey: CryptoCrossSigningKey) {
         // update signatures?
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt
index 52d0124c2bc3d386bcff82216ca20c290afb2c72..e5bdd2aa9b7c436396832b9d412e1374ca1d7199 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt
@@ -72,16 +72,20 @@ internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4)
                 ?.addField(CryptoMetadataEntityFields.X_SIGN_SELF_SIGNED_PRIVATE_KEY, String::class.java)
 
         val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build()
-        val listMigrationAdapter = moshi.adapter<List<String>>(Types.newParameterizedType(
-                List::class.java,
-                String::class.java,
-                Any::class.java
-        ))
-        val mapMigrationAdapter = moshi.adapter<JsonDict>(Types.newParameterizedType(
-                Map::class.java,
-                String::class.java,
-                Any::class.java
-        ))
+        val listMigrationAdapter = moshi.adapter<List<String>>(
+                Types.newParameterizedType(
+                        List::class.java,
+                        String::class.java,
+                        Any::class.java
+                )
+        )
+        val mapMigrationAdapter = moshi.adapter<JsonDict>(
+                Types.newParameterizedType(
+                        Map::class.java,
+                        String::class.java,
+                        Any::class.java
+                )
+        )
 
         realm.schema.get("DeviceInfoEntity")
                 ?.addField(DeviceInfoEntityFields.USER_ID, String::class.java)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo005.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo005.kt
index e1d759876708ad992e6b817118da8df298a690c6..8ec2932a8f6dbaefcd07b184bb13df53206460de 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo005.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo005.kt
@@ -17,9 +17,6 @@
 package org.matrix.android.sdk.internal.crypto.store.db.migration
 
 import io.realm.DynamicRealm
-import org.matrix.android.sdk.internal.crypto.store.db.model.GossipingEventEntityFields
-import org.matrix.android.sdk.internal.crypto.store.db.model.IncomingGossipingRequestEntityFields
-import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingGossipingRequestEntityFields
 import org.matrix.android.sdk.internal.util.database.RealmMigrator
 
 internal class MigrateCryptoTo005(realm: DynamicRealm) : RealmMigrator(realm, 5) {
@@ -29,38 +26,37 @@ internal class MigrateCryptoTo005(realm: DynamicRealm) : RealmMigrator(realm, 5)
         realm.schema.remove("IncomingRoomKeyRequestEntity")
 
         // Not need to migrate existing request, just start fresh?
-
         realm.schema.create("GossipingEventEntity")
-                .addField(GossipingEventEntityFields.TYPE, String::class.java)
-                .addIndex(GossipingEventEntityFields.TYPE)
-                .addField(GossipingEventEntityFields.CONTENT, String::class.java)
-                .addField(GossipingEventEntityFields.SENDER, String::class.java)
-                .addIndex(GossipingEventEntityFields.SENDER)
-                .addField(GossipingEventEntityFields.DECRYPTION_RESULT_JSON, String::class.java)
-                .addField(GossipingEventEntityFields.DECRYPTION_ERROR_CODE, String::class.java)
-                .addField(GossipingEventEntityFields.AGE_LOCAL_TS, Long::class.java)
-                .setNullable(GossipingEventEntityFields.AGE_LOCAL_TS, true)
-                .addField(GossipingEventEntityFields.SEND_STATE_STR, String::class.java)
+                .addField("type", String::class.java)
+                .addIndex("type")
+                .addField("content", String::class.java)
+                .addField("sender", String::class.java)
+                .addIndex("sender")
+                .addField("decryptionResultJson", String::class.java)
+                .addField("decryptionErrorCode", String::class.java)
+                .addField("ageLocalTs", Long::class.java)
+                .setNullable("ageLocalTs", true)
+                .addField("sendStateStr", String::class.java)
 
         realm.schema.create("IncomingGossipingRequestEntity")
-                .addField(IncomingGossipingRequestEntityFields.REQUEST_ID, String::class.java)
-                .addIndex(IncomingGossipingRequestEntityFields.REQUEST_ID)
-                .addField(IncomingGossipingRequestEntityFields.TYPE_STR, String::class.java)
-                .addIndex(IncomingGossipingRequestEntityFields.TYPE_STR)
-                .addField(IncomingGossipingRequestEntityFields.OTHER_USER_ID, String::class.java)
-                .addField(IncomingGossipingRequestEntityFields.REQUESTED_INFO_STR, String::class.java)
-                .addField(IncomingGossipingRequestEntityFields.OTHER_DEVICE_ID, String::class.java)
-                .addField(IncomingGossipingRequestEntityFields.REQUEST_STATE_STR, String::class.java)
-                .addField(IncomingGossipingRequestEntityFields.LOCAL_CREATION_TIMESTAMP, Long::class.java)
-                .setNullable(IncomingGossipingRequestEntityFields.LOCAL_CREATION_TIMESTAMP, true)
+                .addField("requestId", String::class.java)
+                .addIndex("requestId")
+                .addField("typeStr", String::class.java)
+                .addIndex("typeStr")
+                .addField("otherUserId", String::class.java)
+                .addField("requestedInfoStr", String::class.java)
+                .addField("otherDeviceId", String::class.java)
+                .addField("requestStateStr", String::class.java)
+                .addField("localCreationTimestamp", Long::class.java)
+                .setNullable("localCreationTimestamp", true)
 
         realm.schema.create("OutgoingGossipingRequestEntity")
-                .addField(OutgoingGossipingRequestEntityFields.REQUEST_ID, String::class.java)
-                .addIndex(OutgoingGossipingRequestEntityFields.REQUEST_ID)
-                .addField(OutgoingGossipingRequestEntityFields.RECIPIENTS_DATA, String::class.java)
-                .addField(OutgoingGossipingRequestEntityFields.REQUESTED_INFO_STR, String::class.java)
-                .addField(OutgoingGossipingRequestEntityFields.TYPE_STR, String::class.java)
-                .addIndex(OutgoingGossipingRequestEntityFields.TYPE_STR)
-                .addField(OutgoingGossipingRequestEntityFields.REQUEST_STATE_STR, String::class.java)
+                .addField("requestId", String::class.java)
+                .addIndex("requestId")
+                .addField("recipientsData", String::class.java)
+                .addField("requestedInfoStr", String::class.java)
+                .addField("typeStr", String::class.java)
+                .addIndex("typeStr")
+                .addField("requestStateStr", String::class.java)
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo007.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo007.kt
index 718b9787d268684a16dec7d8784869bbd2569880..0e221e78f33c6ebed166ad8cae78bab4de7d2f79 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo007.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo007.kt
@@ -42,7 +42,7 @@ internal class MigrateCryptoTo007(realm: DynamicRealm) : RealmMigrator(realm, 7)
                 val jsonSignatures = crossSigningKeysMapper.serializeSignatures(objectSignatures)
                 it.setString(KeyInfoEntityFields.SIGNATURES, jsonSignatures)
             }
-        } catch (failure: Throwable) {
+        } catch (ignore: Throwable) {
         }
 
         // Migrate frozen classes
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo016.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo016.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5a14ebf85ae5b0f93df9ef91d8a7770f189747d8
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo016.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.internal.crypto.store.db.migration
+
+import io.realm.DynamicRealm
+import org.matrix.android.sdk.internal.crypto.store.db.model.AuditTrailEntityFields
+import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMetadataEntityFields
+import org.matrix.android.sdk.internal.crypto.store.db.model.KeyRequestReplyEntityFields
+import org.matrix.android.sdk.internal.crypto.store.db.model.OutgoingKeyRequestEntityFields
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+
+internal class MigrateCryptoTo016(realm: DynamicRealm) : RealmMigrator(realm, 16) {
+
+    override fun doMigrate(realm: DynamicRealm) {
+        realm.schema.remove("OutgoingGossipingRequestEntity")
+        realm.schema.remove("IncomingGossipingRequestEntity")
+        realm.schema.remove("GossipingEventEntity")
+
+        // No need to migrate existing request, just start fresh
+
+        val replySchema = realm.schema.create("KeyRequestReplyEntity")
+                .addField(KeyRequestReplyEntityFields.SENDER_ID, String::class.java)
+                .addField(KeyRequestReplyEntityFields.FROM_DEVICE, String::class.java)
+                .addField(KeyRequestReplyEntityFields.EVENT_JSON, String::class.java)
+
+        realm.schema.create("OutgoingKeyRequestEntity")
+                .addField(OutgoingKeyRequestEntityFields.REQUEST_ID, String::class.java)
+                .addIndex(OutgoingKeyRequestEntityFields.REQUEST_ID)
+                .addField(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID, String::class.java)
+                .addIndex(OutgoingKeyRequestEntityFields.MEGOLM_SESSION_ID)
+                .addRealmListField(OutgoingKeyRequestEntityFields.REPLIES.`$`, replySchema)
+                .addField(OutgoingKeyRequestEntityFields.RECIPIENTS_DATA, String::class.java)
+                .addField(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR, String::class.java)
+                .addIndex(OutgoingKeyRequestEntityFields.REQUEST_STATE_STR)
+                .addField(OutgoingKeyRequestEntityFields.REQUESTED_INFO_STR, String::class.java)
+                .addField(OutgoingKeyRequestEntityFields.ROOM_ID, String::class.java)
+                .addIndex(OutgoingKeyRequestEntityFields.ROOM_ID)
+                .addField(OutgoingKeyRequestEntityFields.REQUESTED_INDEX, Integer::class.java)
+                .addField(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, Long::class.java)
+                .setNullable(OutgoingKeyRequestEntityFields.CREATION_TIME_STAMP, true)
+
+        realm.schema.create("AuditTrailEntity")
+                .addField(AuditTrailEntityFields.AGE_LOCAL_TS, Long::class.java)
+                .setNullable(AuditTrailEntityFields.AGE_LOCAL_TS, true)
+                .addField(AuditTrailEntityFields.CONTENT_JSON, String::class.java)
+                .addField(AuditTrailEntityFields.TYPE, String::class.java)
+                .addIndex(AuditTrailEntityFields.TYPE)
+
+        realm.schema.get("CryptoMetadataEntity")
+                ?.addField(CryptoMetadataEntityFields.GLOBAL_ENABLE_KEY_GOSSIPING, Boolean::class.java)
+                ?.transform {
+                    // set the default value to true
+                    it.setBoolean(CryptoMetadataEntityFields.GLOBAL_ENABLE_KEY_GOSSIPING, true)
+                }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/GossipingRequestState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailEntity.kt
similarity index 60%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/GossipingRequestState.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailEntity.kt
index d9a6f4fcba1af402522b1b29ead0466f4e008630..2e0e9c8c8ba4d2efec66697a563153c01bcadc93 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/GossipingRequestState.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailEntity.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,18 +14,15 @@
  * limitations under the License.
  */
 
-package org.matrix.android.sdk.api.session.crypto.model
+package org.matrix.android.sdk.internal.crypto.store.db.model
 
-enum class GossipingRequestState {
-    NONE,
-    PENDING,
-    REJECTED,
-    ACCEPTING,
-    ACCEPTED,
-    FAILED_TO_ACCEPTED,
+import io.realm.RealmObject
+import io.realm.annotations.Index
 
-    // USER_REJECTED,
-    UNABLE_TO_PROCESS,
-    CANCELLED_BY_REQUESTER,
-    RE_REQUESTED
+internal open class AuditTrailEntity(
+        var ageLocalTs: Long? = null,
+        @Index var type: String? = null,
+        var contentJson: String? = null
+) : RealmObject() {
+    companion object
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..80ae4a8d0d39ec3c79f8dc99cb51b19b303670d8
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.internal.crypto.store.db.model
+
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.session.crypto.model.AuditTrail
+import org.matrix.android.sdk.api.session.crypto.model.ForwardInfo
+import org.matrix.android.sdk.api.session.crypto.model.IncomingKeyRequestInfo
+import org.matrix.android.sdk.api.session.crypto.model.TrailType
+import org.matrix.android.sdk.api.session.crypto.model.UnknownInfo
+import org.matrix.android.sdk.api.session.crypto.model.WithheldInfo
+import org.matrix.android.sdk.internal.di.MoshiProvider
+
+internal object AuditTrailMapper {
+
+    fun map(entity: AuditTrailEntity): AuditTrail? {
+        val contentJson = entity.contentJson ?: return null
+        return when (entity.type) {
+            TrailType.OutgoingKeyForward.name  -> {
+                val info = tryOrNull {
+                    MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).fromJson(contentJson)
+                } ?: return null
+                AuditTrail(
+                        ageLocalTs = entity.ageLocalTs ?: 0,
+                        type = TrailType.OutgoingKeyForward,
+                        info = info
+                )
+            }
+            TrailType.OutgoingKeyWithheld.name -> {
+                val info = tryOrNull {
+                    MoshiProvider.providesMoshi().adapter(WithheldInfo::class.java).fromJson(contentJson)
+                } ?: return null
+                AuditTrail(
+                        ageLocalTs = entity.ageLocalTs ?: 0,
+                        type = TrailType.OutgoingKeyWithheld,
+                        info = info
+                )
+            }
+            TrailType.IncomingKeyRequest.name  -> {
+                val info = tryOrNull {
+                    MoshiProvider.providesMoshi().adapter(IncomingKeyRequestInfo::class.java).fromJson(contentJson)
+                } ?: return null
+                AuditTrail(
+                        ageLocalTs = entity.ageLocalTs ?: 0,
+                        type = TrailType.IncomingKeyRequest,
+                        info = info
+                )
+            }
+            TrailType.IncomingKeyForward.name  -> {
+                val info = tryOrNull {
+                    MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).fromJson(contentJson)
+                } ?: return null
+                AuditTrail(
+                        ageLocalTs = entity.ageLocalTs ?: 0,
+                        type = TrailType.IncomingKeyForward,
+                        info = info
+                )
+            }
+            else                               -> {
+                AuditTrail(
+                        ageLocalTs = entity.ageLocalTs ?: 0,
+                        type = TrailType.Unknown,
+                        info = UnknownInfo
+                )
+            }
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMapper.kt
index c71d5e73a228b1f755ee703c350466943e8d9661..ca41930f80eb5902d237ac18654719c9fd88506a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMapper.kt
@@ -27,21 +27,27 @@ import timber.log.Timber
 internal object CryptoMapper {
 
     private val moshi = Moshi.Builder().add(SerializeNulls.JSON_ADAPTER_FACTORY).build()
-    private val listMigrationAdapter = moshi.adapter<List<String>>(Types.newParameterizedType(
-            List::class.java,
-            String::class.java,
-            Any::class.java
-    ))
-    private val mapMigrationAdapter = moshi.adapter<JsonDict>(Types.newParameterizedType(
-            Map::class.java,
-            String::class.java,
-            Any::class.java
-    ))
-    private val mapOfStringMigrationAdapter = moshi.adapter<Map<String, Map<String, String>>>(Types.newParameterizedType(
-            Map::class.java,
-            String::class.java,
-            Any::class.java
-    ))
+    private val listMigrationAdapter = moshi.adapter<List<String>>(
+            Types.newParameterizedType(
+                    List::class.java,
+                    String::class.java,
+                    Any::class.java
+            )
+    )
+    private val mapMigrationAdapter = moshi.adapter<JsonDict>(
+            Types.newParameterizedType(
+                    Map::class.java,
+                    String::class.java,
+                    Any::class.java
+            )
+    )
+    private val mapOfStringMigrationAdapter = moshi.adapter<Map<String, Map<String, String>>>(
+            Types.newParameterizedType(
+                    Map::class.java,
+                    String::class.java,
+                    Any::class.java
+            )
+    )
 
     internal fun mapToEntity(deviceInfo: CryptoDeviceInfo): DeviceInfoEntity {
         return DeviceInfoEntity(primaryKey = DeviceInfoEntity.createPrimaryKey(deviceInfo.userId, deviceInfo.deviceId))
@@ -91,11 +97,13 @@ internal object CryptoMapper {
                 },
                 keys = deviceInfoEntity.keysMapJson?.let {
                     try {
-                        moshi.adapter<Map<String, String>>(Types.newParameterizedType(
-                                Map::class.java,
-                                String::class.java,
-                                Any::class.java
-                        )).fromJson(it)
+                        moshi.adapter<Map<String, String>>(
+                                Types.newParameterizedType(
+                                        Map::class.java,
+                                        String::class.java,
+                                        Any::class.java
+                                )
+                        ).fromJson(it)
                     } catch (failure: Throwable) {
                         Timber.e(failure)
                         null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMetadataEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMetadataEntity.kt
index 35ae86db8bb00b034d0d8bed75898fb7e5a7f3cf..63ed0e537e45eaddd479b3223e43c19178a2b3f3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMetadataEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CryptoMetadataEntity.kt
@@ -33,6 +33,8 @@ internal open class CryptoMetadataEntity(
         var deviceSyncToken: String? = null,
         // Settings for blacklisting unverified devices.
         var globalBlacklistUnverifiedDevices: Boolean = false,
+        // setting to enable or disable key gossiping
+        var globalEnableKeyGossiping: Boolean = true,
         // The keys backup version currently used. Null means no backup.
         var backupVersion: String? = null,
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/GossipingEventEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/GossipingEventEntity.kt
deleted file mode 100644
index a024e092b7c40e0f2644a016395f8385cdaa9ee2..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/GossipingEventEntity.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto.store.db.model
-
-import com.squareup.moshi.JsonDataException
-import io.realm.RealmObject
-import io.realm.annotations.Index
-import org.matrix.android.sdk.api.session.crypto.MXCryptoError
-import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult
-import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.room.send.SendState
-import org.matrix.android.sdk.internal.database.mapper.ContentMapper
-import org.matrix.android.sdk.internal.di.MoshiProvider
-import timber.log.Timber
-
-/**
- * Keep track of gossiping event received in toDevice messages
- * (room key request, or sss secret sharing, as well as cancellations)
- *
- */
-internal open class GossipingEventEntity(@Index var type: String? = "",
-                                         var content: String? = null,
-                                         @Index var sender: String? = null,
-                                         var decryptionResultJson: String? = null,
-                                         var decryptionErrorCode: String? = null,
-                                         var ageLocalTs: Long? = null) : RealmObject() {
-
-    private var sendStateStr: String = SendState.UNKNOWN.name
-
-    var sendState: SendState
-        get() {
-            return SendState.valueOf(sendStateStr)
-        }
-        set(value) {
-            sendStateStr = value.name
-        }
-
-    companion object
-
-    fun setDecryptionResult(result: MXEventDecryptionResult) {
-        val decryptionResult = OlmDecryptionResult(
-                payload = result.clearEvent,
-                senderKey = result.senderCurve25519Key,
-                keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
-                forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
-        )
-        val adapter = MoshiProvider.providesMoshi().adapter<OlmDecryptionResult>(OlmDecryptionResult::class.java)
-        decryptionResultJson = adapter.toJson(decryptionResult)
-        decryptionErrorCode = null
-    }
-
-    fun toModel(): Event {
-        return Event(
-                type = this.type ?: "",
-                content = ContentMapper.map(this.content),
-                senderId = this.sender
-        ).also {
-            it.ageLocalTs = this.ageLocalTs
-            it.sendState = this.sendState
-            this.decryptionResultJson?.let { json ->
-                try {
-                    it.mxDecryptionResult = MoshiProvider.providesMoshi().adapter(OlmDecryptionResult::class.java).fromJson(json)
-                } catch (t: JsonDataException) {
-                    Timber.e(t, "Failed to parse decryption result")
-                }
-            }
-            // TODO get the full crypto error object
-            it.mCryptoError = this.decryptionErrorCode?.let { errorCode ->
-                MXCryptoError.ErrorType.valueOf(errorCode)
-            }
-        }
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/IncomingGossipingRequestEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/IncomingGossipingRequestEntity.kt
deleted file mode 100644
index f05c8853c8dc60aa68416f82efed3b98b689dc7f..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/IncomingGossipingRequestEntity.kt
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto.store.db.model
-
-import io.realm.RealmObject
-import io.realm.annotations.Index
-import org.matrix.android.sdk.api.extensions.tryOrNull
-import org.matrix.android.sdk.api.session.crypto.model.GossipingRequestState
-import org.matrix.android.sdk.api.session.crypto.model.IncomingRoomKeyRequest
-import org.matrix.android.sdk.api.session.crypto.model.IncomingSecretShareRequest
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
-import org.matrix.android.sdk.internal.crypto.GossipRequestType
-import org.matrix.android.sdk.internal.crypto.IncomingShareRequestCommon
-
-internal open class IncomingGossipingRequestEntity(@Index var requestId: String? = "",
-                                                   @Index var typeStr: String? = null,
-                                                   var otherUserId: String? = null,
-                                                   var requestedInfoStr: String? = null,
-                                                   var otherDeviceId: String? = null,
-                                                   var localCreationTimestamp: Long? = null
-) : RealmObject() {
-
-    fun getRequestedSecretName(): String? = if (type == GossipRequestType.SECRET) {
-        requestedInfoStr
-    } else null
-
-    fun getRequestedKeyInfo(): RoomKeyRequestBody? = if (type == GossipRequestType.KEY) {
-        RoomKeyRequestBody.fromJson(requestedInfoStr)
-    } else null
-
-    var type: GossipRequestType
-        get() {
-            return tryOrNull { typeStr?.let { GossipRequestType.valueOf(it) } } ?: GossipRequestType.KEY
-        }
-        set(value) {
-            typeStr = value.name
-        }
-
-    private var requestStateStr: String = GossipingRequestState.NONE.name
-
-    var requestState: GossipingRequestState
-        get() {
-            return tryOrNull { GossipingRequestState.valueOf(requestStateStr) }
-                    ?: GossipingRequestState.NONE
-        }
-        set(value) {
-            requestStateStr = value.name
-        }
-
-    companion object
-
-    fun toIncomingGossipingRequest(): IncomingShareRequestCommon {
-        return when (type) {
-            GossipRequestType.KEY    -> {
-                IncomingRoomKeyRequest(
-                        requestBody = getRequestedKeyInfo(),
-                        deviceId = otherDeviceId,
-                        userId = otherUserId,
-                        requestId = requestId,
-                        state = requestState,
-                        localCreationTimestamp = localCreationTimestamp
-                )
-            }
-            GossipRequestType.SECRET -> {
-                IncomingSecretShareRequest(
-                        secretName = getRequestedSecretName(),
-                        deviceId = otherDeviceId,
-                        userId = otherUserId,
-                        requestId = requestId,
-                        localCreationTimestamp = localCreationTimestamp
-                )
-            }
-        }
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyRequestReplyEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyRequestReplyEntity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0c7cf79e788a6b3dcbab91e35c73c179e028fd4e
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyRequestReplyEntity.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.internal.crypto.store.db.model
+
+import io.realm.RealmObject
+import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.internal.di.MoshiProvider
+
+internal open class KeyRequestReplyEntity(
+        var senderId: String? = null,
+        var fromDevice: String? = null,
+        var eventJson: String? = null
+) : RealmObject() {
+    companion object
+
+    fun getEvent(): Event? {
+        return eventJson?.let {
+            MoshiProvider.providesMoshi().adapter(Event::class.java).fromJson(it)
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/MyDeviceLastSeenInfoEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/MyDeviceLastSeenInfoEntity.kt
index 222711f9acf60a068ef5d1aa58ffb3b563d87375..74a81d5b01a045328d01edd8b4749cb1a7782084 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/MyDeviceLastSeenInfoEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/MyDeviceLastSeenInfoEntity.kt
@@ -20,13 +20,13 @@ import io.realm.RealmObject
 import io.realm.annotations.PrimaryKey
 
 internal open class MyDeviceLastSeenInfoEntity(
-        /**The device id*/
+        /** The device id. */
         @PrimaryKey var deviceId: String? = null,
-        /** The device display name*/
+        /** The device display name. */
         var displayName: String? = null,
         /** The last time this device has been seen. */
         var lastSeenTs: Long? = null,
-        /** The last ip address*/
+        /** The last ip address. */
         var lastSeenIp: String? = null
 ) : RealmObject() {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingGossipingRequestEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingGossipingRequestEntity.kt
deleted file mode 100644
index 0e1278967eb4adcb1be665856498c62e6110b555..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingGossipingRequestEntity.kt
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto.store.db.model
-
-import com.squareup.moshi.JsonAdapter
-import com.squareup.moshi.Types
-import io.realm.RealmObject
-import io.realm.annotations.Index
-import org.matrix.android.sdk.api.extensions.tryOrNull
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingGossipingRequestState
-import org.matrix.android.sdk.api.session.crypto.model.OutgoingRoomKeyRequest
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
-import org.matrix.android.sdk.internal.crypto.GossipRequestType
-import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequest
-import org.matrix.android.sdk.internal.crypto.OutgoingSecretRequest
-import org.matrix.android.sdk.internal.di.MoshiProvider
-
-internal open class OutgoingGossipingRequestEntity(
-        @Index var requestId: String? = null,
-        var recipientsData: String? = null,
-        var requestedInfoStr: String? = null,
-        @Index var typeStr: String? = null
-) : RealmObject() {
-
-    fun getRequestedSecretName(): String? = if (type == GossipRequestType.SECRET) {
-        requestedInfoStr
-    } else null
-
-    fun getRequestedKeyInfo(): RoomKeyRequestBody? = if (type == GossipRequestType.KEY) {
-        RoomKeyRequestBody.fromJson(requestedInfoStr)
-    } else null
-
-    var type: GossipRequestType
-        get() {
-            return tryOrNull { typeStr?.let { GossipRequestType.valueOf(it) } } ?: GossipRequestType.KEY
-        }
-        set(value) {
-            typeStr = value.name
-        }
-
-    private var requestStateStr: String = OutgoingGossipingRequestState.UNSENT.name
-
-    var requestState: OutgoingGossipingRequestState
-        get() {
-            return tryOrNull { OutgoingGossipingRequestState.valueOf(requestStateStr) }
-                    ?: OutgoingGossipingRequestState.UNSENT
-        }
-        set(value) {
-            requestStateStr = value.name
-        }
-
-    companion object {
-
-        private val recipientsDataMapper: JsonAdapter<Map<String, List<String>>> =
-                MoshiProvider
-                        .providesMoshi()
-                        .adapter<Map<String, List<String>>>(
-                                Types.newParameterizedType(Map::class.java, String::class.java, List::class.java)
-                        )
-    }
-
-    fun toOutgoingGossipingRequest(): OutgoingGossipingRequest {
-        return when (type) {
-            GossipRequestType.KEY    -> {
-                OutgoingRoomKeyRequest(
-                        requestBody = getRequestedKeyInfo(),
-                        recipients = getRecipients().orEmpty(),
-                        requestId = requestId ?: "",
-                        state = requestState
-                )
-            }
-            GossipRequestType.SECRET -> {
-                OutgoingSecretRequest(
-                        secretName = getRequestedSecretName(),
-                        recipients = getRecipients().orEmpty(),
-                        requestId = requestId ?: "",
-                        state = requestState
-                )
-            }
-        }
-    }
-
-    private fun getRecipients(): Map<String, List<String>>? {
-        return this.recipientsData?.let { recipientsDataMapper.fromJson(it) }
-    }
-
-    fun setRecipients(recipients: Map<String, List<String>>) {
-        this.recipientsData = recipientsDataMapper.toJson(recipients)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7a8ba188093879501e5033e7066debdc34f7f6f1
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.internal.crypto.store.db.model
+
+import com.squareup.moshi.JsonAdapter
+import com.squareup.moshi.Types
+import io.realm.RealmList
+import io.realm.RealmObject
+import io.realm.annotations.Index
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest
+import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState
+import org.matrix.android.sdk.api.session.crypto.RequestReply
+import org.matrix.android.sdk.api.session.crypto.RequestResult
+import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
+import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
+import org.matrix.android.sdk.api.session.events.model.toModel
+import org.matrix.android.sdk.internal.di.MoshiProvider
+
+internal open class OutgoingKeyRequestEntity(
+        @Index var requestId: String? = null,
+        var requestedIndex: Int? = null,
+        var recipientsData: String? = null,
+        var requestedInfoStr: String? = null,
+        var creationTimeStamp: Long? = null,
+        // de-normalization for better query (if not have to query all and parse json)
+        @Index var roomId: String? = null,
+        @Index var megolmSessionId: String? = null,
+
+        var replies: RealmList<KeyRequestReplyEntity> = RealmList()
+) : RealmObject() {
+
+    @Index private var requestStateStr: String = OutgoingRoomKeyRequestState.UNSENT.name
+
+    companion object {
+
+        private val recipientsDataMapper: JsonAdapter<Map<String, List<String>>> =
+                MoshiProvider
+                        .providesMoshi()
+                        .adapter(
+                                Types.newParameterizedType(Map::class.java, String::class.java, List::class.java)
+                        )
+    }
+
+    private fun getRequestedKeyInfo(): RoomKeyRequestBody? = RoomKeyRequestBody.fromJson(requestedInfoStr)
+
+    fun setRequestBody(body: RoomKeyRequestBody) {
+        requestedInfoStr = body.toJson()
+        roomId = body.roomId
+        megolmSessionId = body.sessionId
+    }
+
+    var requestState: OutgoingRoomKeyRequestState
+        get() {
+            return tryOrNull { OutgoingRoomKeyRequestState.valueOf(requestStateStr) }
+                    ?: OutgoingRoomKeyRequestState.UNSENT
+        }
+        set(value) {
+            requestStateStr = value.name
+        }
+
+    private fun getRecipients(): Map<String, List<String>>? {
+        return this.recipientsData?.let { recipientsDataMapper.fromJson(it) }
+    }
+
+    fun setRecipients(recipients: Map<String, List<String>>) {
+        this.recipientsData = recipientsDataMapper.toJson(recipients)
+    }
+
+    fun addReply(userId: String, fromDevice: String?, event: Event) {
+        val newReply = KeyRequestReplyEntity(
+                senderId = userId,
+                fromDevice = fromDevice,
+                eventJson = MoshiProvider.providesMoshi().adapter(Event::class.java).toJson(event)
+        )
+        replies.add(newReply)
+    }
+
+    fun toOutgoingKeyRequest(): OutgoingKeyRequest {
+        return OutgoingKeyRequest(
+                requestBody = getRequestedKeyInfo(),
+                recipients = getRecipients().orEmpty(),
+                requestId = requestId ?: "",
+                fromIndex = requestedIndex ?: 0,
+                state = requestState,
+                results = replies.mapNotNull { entity ->
+                    val userId = entity.senderId ?: return@mapNotNull null
+                    val result = entity.eventJson?.let {
+                        MoshiProvider.providesMoshi().adapter(Event::class.java).fromJson(it)
+                    }?.let { event ->
+                        eventToResult(event)
+                    } ?: return@mapNotNull null
+                    RequestReply(
+                            userId = userId,
+                            fromDevice = entity.fromDevice,
+                            result = result
+                    )
+                }
+        )
+    }
+
+    private fun eventToResult(event: Event): RequestResult? {
+        return when (event.getClearType()) {
+            EventType.ROOM_KEY_WITHHELD  -> {
+                event.content.toModel<RoomKeyWithHeldContent>()?.code?.let {
+                    RequestResult.Failure(it)
+                }
+            }
+            EventType.FORWARDED_ROOM_KEY -> {
+                RequestResult.Success((event.content?.get("chain_index") as? Number)?.toInt() ?: 0)
+            }
+            else                         -> null
+        }
+    }
+}
+
+internal fun OutgoingKeyRequestEntity.deleteOnCascade() {
+    replies.deleteAllFromRealm()
+    deleteFromRealm()
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/CryptoRoomEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/CryptoRoomEntityQueries.kt
index 5750cc1f67675cf1bd21468154f062108681597e..68c49740716d71cbdedada983132cf191e195f1b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/CryptoRoomEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/CryptoRoomEntityQueries.kt
@@ -23,14 +23,14 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoRoomEntityFields
 
 /**
- * Get or create a room
+ * Get or create a room.
  */
 internal fun CryptoRoomEntity.Companion.getOrCreate(realm: Realm, roomId: String): CryptoRoomEntity {
     return getById(realm, roomId) ?: realm.createObject(roomId)
 }
 
 /**
- * Get a room
+ * Get a room.
  */
 internal fun CryptoRoomEntity.Companion.getById(realm: Realm, roomId: String): CryptoRoomEntity? {
     return realm.where<CryptoRoomEntity>()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/DeviceInfoEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/DeviceInfoEntityQueries.kt
index c9523d63ce3b3aae57d268a2fb5ec99048708301..0a922e79bceb25296897215b9d5da3442f9b3ba7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/DeviceInfoEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/DeviceInfoEntityQueries.kt
@@ -24,7 +24,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.DeviceInfoEntityFie
 import org.matrix.android.sdk.internal.crypto.store.db.model.createPrimaryKey
 
 /**
- * Get or create a device info
+ * Get or create a device info.
  */
 internal fun DeviceInfoEntity.Companion.getOrCreate(realm: Realm, userId: String, deviceId: String): DeviceInfoEntity {
     val key = DeviceInfoEntity.createPrimaryKey(userId, deviceId)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/UserEntitiesQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/UserEntitiesQueries.kt
index 5a3b8e53975c4f45891b7b8d4ddd1915804a4366..73c399743998c1fee687d1a972a4c2333efb8460 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/UserEntitiesQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/UserEntitiesQueries.kt
@@ -24,7 +24,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
 import org.matrix.android.sdk.internal.crypto.store.db.model.deleteOnCascade
 
 /**
- * Get or create a user
+ * Get or create a user.
  */
 internal fun UserEntity.Companion.getOrCreate(realm: Realm, userId: String): UserEntity {
     return realm.where<UserEntity>()
@@ -34,7 +34,7 @@ internal fun UserEntity.Companion.getOrCreate(realm: Realm, userId: String): Use
 }
 
 /**
- * Delete a user
+ * Delete a user.
  */
 internal fun UserEntity.Companion.delete(realm: Realm, userId: String) {
     realm.where<UserEntity>()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt
index 1e395796a98a3c147cb00a9b118e071d8a0f1f6f..394c6189681ca919ebc27e78efd6fa6e6e6f2096 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt
@@ -15,6 +15,7 @@
  */
 package org.matrix.android.sdk.internal.crypto.tasks
 
+import dagger.Lazy
 import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
 import org.matrix.android.sdk.api.session.crypto.CryptoService
 import org.matrix.android.sdk.api.session.crypto.model.MXEncryptEventContentResult
@@ -39,7 +40,7 @@ internal interface EncryptEventTask : Task<EncryptEventTask.Params, Event> {
 
 internal class DefaultEncryptEventTask @Inject constructor(
         private val localEchoRepository: LocalEchoRepository,
-        private val cryptoService: CryptoService
+        private val cryptoService: Lazy<CryptoService>
 ) : EncryptEventTask {
     override suspend fun execute(params: EncryptEventTask.Params): Event {
         // don't want to wait for any query
@@ -59,7 +60,7 @@ internal class DefaultEncryptEventTask @Inject constructor(
 //        try {
         // let it throws
         awaitCallback<MXEncryptEventContentResult> {
-            cryptoService.encryptEventContent(localMutableContent, localEvent.type, params.roomId, it)
+            cryptoService.get().encryptEventContent(localMutableContent, localEvent.type, params.roomId, it)
         }.let { result ->
             val modifiedContent = HashMap(result.eventContent)
             params.keepKeys?.forEach { toKeep ->
@@ -80,7 +81,7 @@ internal class DefaultEncryptEventTask @Inject constructor(
                         ).toContent(),
                         forwardingCurve25519KeyChain = emptyList(),
                         senderCurve25519Key = result.eventContent["sender_key"] as? String,
-                        claimedEd25519Key = cryptoService.getMyDevice().fingerprint()
+                        claimedEd25519Key = cryptoService.get().getMyDevice().fingerprint()
                 )
             } else {
                 null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt
index bdfe818c6206afec42c5c7bc9257671c988a99f9..50efe51bc1bb1502d58f7156f863f6bbb46c56ac 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt
@@ -15,6 +15,7 @@
  */
 package org.matrix.android.sdk.internal.crypto.tasks
 
+import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.room.send.SendState
 import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
@@ -46,7 +47,9 @@ internal class DefaultSendEventTask @Inject constructor(
             params.event.roomId
                     ?.takeIf { params.encrypt }
                     ?.let { roomId ->
-                        loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId))
+                        tryOrNull {
+                            loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId))
+                        }
                     }
 
             val event = handleEncryption(params)
@@ -66,6 +69,7 @@ internal class DefaultSendEventTask @Inject constructor(
             }
         } catch (e: Throwable) {
 //            localEchoRepository.updateSendState(params.event.eventId!!, SendState.UNDELIVERED)
+            Timber.w(e, "Unable to send the Event")
             throw e
         }
     }
@@ -73,11 +77,13 @@ internal class DefaultSendEventTask @Inject constructor(
     @Throws
     private suspend fun handleEncryption(params: SendEventTask.Params): Event {
         if (params.encrypt && !params.event.isEncrypted()) {
-            return encryptEventTask.execute(EncryptEventTask.Params(
-                    params.event.roomId ?: "",
-                    params.event,
-                    listOf("m.relates_to")
-            ))
+            return encryptEventTask.execute(
+                    EncryptEventTask.Params(
+                            params.event.roomId ?: "",
+                            params.event,
+                            listOf("m.relates_to")
+                    )
+            )
         }
         return params.event
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt
index c4a6ba27d6834db29cbd9e5e5193f62874889518..7c52c62d92f218ebb593b577aee2724da54ba319 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt
@@ -47,7 +47,7 @@ internal class DefaultSendVerificationMessageTask @Inject constructor(
             localEchoRepository.updateSendState(localId, event.roomId, SendState.SENDING)
             val response = executeRequest(globalErrorReceiver) {
                 roomAPI.send(
-                        localId,
+                        txId = localId,
                         roomId = event.roomId ?: "",
                         content = event.content,
                         eventType = event.type ?: ""
@@ -64,11 +64,13 @@ internal class DefaultSendVerificationMessageTask @Inject constructor(
     private suspend fun handleEncryption(params: SendVerificationMessageTask.Params): Event {
         if (cryptoSessionInfoProvider.isRoomEncrypted(params.event.roomId ?: "")) {
             try {
-                return encryptEventTask.execute(EncryptEventTask.Params(
-                        params.event.roomId ?: "",
-                        params.event,
-                        listOf("m.relates_to")
-                ))
+                return encryptEventTask.execute(
+                        EncryptEventTask.Params(
+                                params.event.roomId ?: "",
+                                params.event,
+                                listOf("m.relates_to")
+                        )
+                )
             } catch (throwable: Throwable) {
                 // We said it's ok to send verification request in clear
             }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSignaturesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSignaturesTask.kt
index e03e353cb1caa3dff8ec5e64b88e4b434631a4fd..18d8b265589a6affbc98975d0c597a5c858f9402 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSignaturesTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSignaturesTask.kt
@@ -15,7 +15,6 @@
  */
 package org.matrix.android.sdk.internal.crypto.tasks
 
-import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.internal.crypto.api.CryptoApi
 import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
 import org.matrix.android.sdk.internal.network.executeRequest
@@ -34,20 +33,15 @@ internal class DefaultUploadSignaturesTask @Inject constructor(
 ) : UploadSignaturesTask {
 
     override suspend fun execute(params: UploadSignaturesTask.Params) {
-        try {
-            val response = executeRequest(
-                    globalErrorReceiver,
-                    canRetry = true,
-                    maxRetriesCount = 10
-            ) {
-                cryptoApi.uploadSignatures(params.signatures)
-            }
-            if (response.failures?.isNotEmpty() == true) {
-                throw Throwable(response.failures.toString())
-            }
-            return
-        } catch (f: Failure) {
-            throw f
+        val response = executeRequest(
+                globalErrorReceiver,
+                canRetry = true,
+                maxRetriesCount = 10
+        ) {
+            cryptoApi.uploadSignatures(params.signatures)
+        }
+        if (response.failures?.isNotEmpty() == true) {
+            throw Throwable(response.failures.toString())
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSigningKeysTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSigningKeysTask.kt
index 0a0df11bd339b6e5264f3554bd2d62b9fa65d7f0..e539867a040361a9f968d2a6ea574d2994fdc3ae 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSigningKeysTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/UploadSigningKeysTask.kt
@@ -36,7 +36,7 @@ internal interface UploadSigningKeysTask : Task<UploadSigningKeysTask.Params, Un
             // the SSK
             val selfSignedKey: CryptoCrossSigningKey,
             /**
-             * Authorisation info (User Interactive flow)
+             * Authorisation info (User Interactive flow).
              */
             val userAuthParam: UIABaseAuth?
     )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt
index b230f0d02954336bf62b8ca8f72f8917ff4ae4aa..4ab7e0e30c7bc589a052ddaeb756ab2becd90d40 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt
@@ -33,7 +33,7 @@ internal object HkdfSha256 {
     }
 
     /**
-     * HkdfSha256-Extract(salt, IKM) -> PRK
+     * HkdfSha256-Extract(salt, IKM) -> PRK.
      *
      * @param salt  optional salt value (a non-secret random value);
      * if not provided, it is set to a string of HashLen (size in octets) zeros.
@@ -45,7 +45,7 @@ internal object HkdfSha256 {
     }
 
     /**
-     * HkdfSha256-Expand(PRK, info, L) -> OKM
+     * HkdfSha256-Expand(PRK, info, L) -> OKM.
      *
      * @param prk a pseudorandom key of at least HashLen bytes (usually, the output from the extract step)
      * @param info optional context and application specific information (can be empty)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt
index 68f1cf62d52968af554d7b2d7681723dd404ea56..a9d5cf1191d2dce87dd12969b4c066d5b5b2cf15 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt
@@ -23,8 +23,8 @@ import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerific
 import org.matrix.android.sdk.api.session.crypto.verification.SasMode
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
 import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.internal.crypto.IncomingGossipingRequestManager
-import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager
+import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
+import org.matrix.android.sdk.internal.crypto.SecretShareManager
 import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import timber.log.Timber
@@ -35,8 +35,8 @@ internal class DefaultIncomingSASDefaultVerificationTransaction(
         override val deviceId: String?,
         private val cryptoStore: IMXCryptoStore,
         crossSigningService: CrossSigningService,
-        outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
-        incomingGossipingRequestManager: IncomingGossipingRequestManager,
+        outgoingKeyRequestManager: OutgoingKeyRequestManager,
+        secretShareManager: SecretShareManager,
         deviceFingerprint: String,
         transactionId: String,
         otherUserID: String,
@@ -47,13 +47,14 @@ internal class DefaultIncomingSASDefaultVerificationTransaction(
         deviceId,
         cryptoStore,
         crossSigningService,
-        outgoingGossipingRequestManager,
-        incomingGossipingRequestManager,
+        outgoingKeyRequestManager,
+        secretShareManager,
         deviceFingerprint,
         transactionId,
         otherUserID,
         null,
-        isIncoming = true),
+        isIncoming = true
+),
         IncomingSasVerificationTransaction {
 
     override val uxState: IncomingSasVerificationTransaction.UxState
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt
index e0d912a9a62a1e544b3bc8273ec65e736871fac2..ddb8ed232ba1bdc865cbfa313aa3f80d09e269d8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt
@@ -20,8 +20,8 @@ import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
 import org.matrix.android.sdk.api.session.crypto.verification.OutgoingSasVerificationTransaction
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
 import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.internal.crypto.IncomingGossipingRequestManager
-import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager
+import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
+import org.matrix.android.sdk.internal.crypto.SecretShareManager
 import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import timber.log.Timber
@@ -32,8 +32,8 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction(
         deviceId: String?,
         cryptoStore: IMXCryptoStore,
         crossSigningService: CrossSigningService,
-        outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
-        incomingGossipingRequestManager: IncomingGossipingRequestManager,
+        outgoingKeyRequestManager: OutgoingKeyRequestManager,
+        secretShareManager: SecretShareManager,
         deviceFingerprint: String,
         transactionId: String,
         otherUserId: String,
@@ -44,13 +44,14 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction(
         deviceId,
         cryptoStore,
         crossSigningService,
-        outgoingGossipingRequestManager,
-        incomingGossipingRequestManager,
+        outgoingKeyRequestManager,
+        secretShareManager,
         deviceFingerprint,
         transactionId,
         otherUserId,
         otherDeviceId,
-        isIncoming = false),
+        isIncoming = false
+),
         OutgoingSasVerificationTransaction {
 
     override val uxState: OutgoingSasVerificationTransaction.UxState
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt
index d62ca5503d953aac844e79b5369213dd9dc92a39..6da674d6e4aa1ca996e7b5a1134ded5e686a1a7a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt
@@ -59,9 +59,9 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageVerification
 import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationStartContent
 import org.matrix.android.sdk.api.session.room.model.message.ValidVerificationDone
 import org.matrix.android.sdk.internal.crypto.DeviceListManager
-import org.matrix.android.sdk.internal.crypto.IncomingGossipingRequestManager
 import org.matrix.android.sdk.internal.crypto.MyDeviceInfoHolder
-import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager
+import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
+import org.matrix.android.sdk.internal.crypto.SecretShareManager
 import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
 import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationAccept
 import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationCancel
@@ -95,8 +95,8 @@ internal class DefaultVerificationService @Inject constructor(
         @UserId private val userId: String,
         @DeviceId private val deviceId: String?,
         private val cryptoStore: IMXCryptoStore,
-        private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
-        private val incomingGossipingRequestManager: IncomingGossipingRequestManager,
+        private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
+        private val secretShareManager: SecretShareManager,
         private val myDeviceInfoHolder: Lazy<MyDeviceInfoHolder>,
         private val deviceListManager: DeviceListManager,
         private val setDeviceVerificationAction: SetDeviceVerificationAction,
@@ -551,8 +551,8 @@ internal class DefaultVerificationService @Inject constructor(
                             deviceId,
                             cryptoStore,
                             crossSigningService,
-                            outgoingGossipingRequestManager,
-                            incomingGossipingRequestManager,
+                            outgoingKeyRequestManager,
+                            secretShareManager,
                             myDeviceInfoHolder.get().myDevice.fingerprint()!!,
                             startReq.transactionId,
                             otherUserId,
@@ -771,8 +771,15 @@ internal class DefaultVerificationService @Inject constructor(
             return
         }
 
+        val roomId = event.roomId
+        if (roomId == null) {
+            Timber.e("## SAS Verification missing roomId for event")
+            // TODO cancel?
+            return
+        }
+
         handleReadyReceived(event.senderId, readyReq) {
-            verificationTransportRoomMessageFactory.createTransport(event.roomId!!, it)
+            verificationTransportRoomMessageFactory.createTransport(roomId, it)
         }
     }
 
@@ -814,21 +821,15 @@ internal class DefaultVerificationService @Inject constructor(
             getExistingTransaction(userId, doneReq.transactionId)
                     ?: getOldTransaction(userId, doneReq.transactionId)
                             ?.let { vt ->
-                                val otherDeviceId = vt.otherDeviceId
+                                val otherDeviceId = vt.otherDeviceId ?: return@let
                                 if (!crossSigningService.canCrossSign()) {
-                                    outgoingGossipingRequestManager.sendSecretShareRequest(
-                                            MASTER_KEY_SSSS_NAME, mapOf(userId to listOf(otherDeviceId ?: "*"))
-                                    )
-                                    outgoingGossipingRequestManager.sendSecretShareRequest(
-                                            SELF_SIGNING_KEY_SSSS_NAME, mapOf(userId to listOf(otherDeviceId ?: "*"))
-                                    )
-                                    outgoingGossipingRequestManager.sendSecretShareRequest(
-                                            USER_SIGNING_KEY_SSSS_NAME, mapOf(userId to listOf(otherDeviceId ?: "*"))
-                                    )
+                                    cryptoCoroutineScope.launch {
+                                        secretShareManager.requestSecretTo(otherDeviceId, MASTER_KEY_SSSS_NAME)
+                                        secretShareManager.requestSecretTo(otherDeviceId, SELF_SIGNING_KEY_SSSS_NAME)
+                                        secretShareManager.requestSecretTo(otherDeviceId, USER_SIGNING_KEY_SSSS_NAME)
+                                        secretShareManager.requestSecretTo(otherDeviceId, KEYBACKUP_SECRET_SSSS_NAME)
+                                    }
                                 }
-                                outgoingGossipingRequestManager.sendSecretShareRequest(
-                                        KEYBACKUP_SECRET_SSSS_NAME, mapOf(userId to listOf(otherDeviceId ?: "*"))
-                                )
                             }
         }
     }
@@ -922,8 +923,8 @@ internal class DefaultVerificationService @Inject constructor(
                     otherUserId = senderId,
                     otherDeviceId = readyReq.fromDevice,
                     crossSigningService = crossSigningService,
-                    outgoingGossipingRequestManager = outgoingGossipingRequestManager,
-                    incomingGossipingRequestManager = incomingGossipingRequestManager,
+                    outgoingKeyRequestManager = outgoingKeyRequestManager,
+                    secretShareManager = secretShareManager,
                     cryptoStore = cryptoStore,
                     qrCodeData = qrCodeData,
                     userId = userId,
@@ -1124,8 +1125,8 @@ internal class DefaultVerificationService @Inject constructor(
                     deviceId,
                     cryptoStore,
                     crossSigningService,
-                    outgoingGossipingRequestManager,
-                    incomingGossipingRequestManager,
+                    outgoingKeyRequestManager,
+                    secretShareManager,
                     myDeviceInfoHolder.get().myDevice.fingerprint()!!,
                     txID,
                     otherUserId,
@@ -1188,6 +1189,7 @@ internal class DefaultVerificationService @Inject constructor(
         }
                 .distinct()
 
+        requestsForUser.add(verificationRequest)
         transport.sendVerificationRequest(methodValues, validLocalId, otherUserId, roomId, null) { syncedId, info ->
             // We need to update with the syncedID
             updatePendingRequest(
@@ -1199,7 +1201,6 @@ internal class DefaultVerificationService @Inject constructor(
             )
         }
 
-        requestsForUser.add(verificationRequest)
         dispatchRequestAdded(verificationRequest)
 
         return verificationRequest
@@ -1323,8 +1324,8 @@ internal class DefaultVerificationService @Inject constructor(
                     deviceId,
                     cryptoStore,
                     crossSigningService,
-                    outgoingGossipingRequestManager,
-                    incomingGossipingRequestManager,
+                    outgoingKeyRequestManager,
+                    secretShareManager,
                     myDeviceInfoHolder.get().myDevice.fingerprint()!!,
                     transactionId,
                     otherUserId,
@@ -1465,8 +1466,8 @@ internal class DefaultVerificationService @Inject constructor(
                         otherUserId = otherUserId,
                         otherDeviceId = otherDeviceId,
                         crossSigningService = crossSigningService,
-                        outgoingGossipingRequestManager = outgoingGossipingRequestManager,
-                        incomingGossipingRequestManager = incomingGossipingRequestManager,
+                        outgoingKeyRequestManager = outgoingKeyRequestManager,
+                        secretShareManager = secretShareManager,
                         cryptoStore = cryptoStore,
                         qrCodeData = qrCodeData,
                         userId = userId,
@@ -1484,7 +1485,7 @@ internal class DefaultVerificationService @Inject constructor(
     }
 
     /**
-     * This string must be unique for the pair of users performing verification for the duration that the transaction is valid
+     * This string must be unique for the pair of users performing verification for the duration that the transaction is valid.
      */
     private fun createUniqueIDForTransaction(otherUserId: String, otherDeviceID: String): String {
         return buildString {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationTransaction.kt
index 69d9388c5ff6754ee4229193c0acef99e8f3c4e9..27bc7643957340efc11441530427c8c9f4c3c3d8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationTransaction.kt
@@ -20,19 +20,19 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningServic
 import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
-import org.matrix.android.sdk.internal.crypto.IncomingGossipingRequestManager
-import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager
+import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
+import org.matrix.android.sdk.internal.crypto.SecretShareManager
 import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
 import timber.log.Timber
 
 /**
- * Generic interactive key verification transaction
+ * Generic interactive key verification transaction.
  */
 internal abstract class DefaultVerificationTransaction(
         private val setDeviceVerificationAction: SetDeviceVerificationAction,
         private val crossSigningService: CrossSigningService,
-        private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
-        private val incomingGossipingRequestManager: IncomingGossipingRequestManager,
+        private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
+        private val secretShareManager: SecretShareManager,
         private val userId: String,
         override val transactionId: String,
         override val otherUserId: String,
@@ -86,7 +86,7 @@ internal abstract class DefaultVerificationTransaction(
         }
 
         if (otherUserId == userId) {
-            incomingGossipingRequestManager.onVerificationCompleteForDevice(otherDeviceId!!)
+            secretShareManager.onVerificationCompleteForDevice(otherDeviceId!!)
 
             // If me it's reasonable to sign and upload the device signature
             // Notice that i might not have the private keys, so may not be able to do it
@@ -105,8 +105,10 @@ internal abstract class DefaultVerificationTransaction(
 
     private fun setDeviceVerified(userId: String, deviceId: String) {
         // TODO should not override cross sign status
-        setDeviceVerificationAction.handle(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true),
+        setDeviceVerificationAction.handle(
+                DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true),
                 userId,
-                deviceId)
+                deviceId
+        )
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt
index 4bf01a28095a6cbf390dc43b5d82623726f1e0d3..68dd57478e62af81575a51f90ea3c1c7d6253343 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt
@@ -23,8 +23,8 @@ import org.matrix.android.sdk.api.session.crypto.verification.SasMode
 import org.matrix.android.sdk.api.session.crypto.verification.SasVerificationTransaction
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
 import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.internal.crypto.IncomingGossipingRequestManager
-import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager
+import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
+import org.matrix.android.sdk.internal.crypto.SecretShareManager
 import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import org.matrix.android.sdk.internal.extensions.toUnsignedInt
@@ -42,8 +42,8 @@ internal abstract class SASDefaultVerificationTransaction(
         open val deviceId: String?,
         private val cryptoStore: IMXCryptoStore,
         crossSigningService: CrossSigningService,
-        outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
-        incomingGossipingRequestManager: IncomingGossipingRequestManager,
+        outgoingKeyRequestManager: OutgoingKeyRequestManager,
+        secretShareManager: SecretShareManager,
         private val deviceFingerprint: String,
         transactionId: String,
         otherUserId: String,
@@ -52,13 +52,14 @@ internal abstract class SASDefaultVerificationTransaction(
 ) : DefaultVerificationTransaction(
         setDeviceVerificationAction,
         crossSigningService,
-        outgoingGossipingRequestManager,
-        incomingGossipingRequestManager,
+        outgoingKeyRequestManager,
+        secretShareManager,
         userId,
         transactionId,
         otherUserId,
         otherDeviceId,
-        isIncoming),
+        isIncoming
+),
         SasVerificationTransaction {
 
     companion object {
@@ -131,7 +132,7 @@ internal abstract class SASDefaultVerificationTransaction(
 
     /**
      * To be called by the client when the user has verified that
-     * both short codes do match
+     * both short codes do match.
      */
     override fun userHasVerifiedShortCode() {
         Timber.v("## SAS short code verified by user for id:$transactionId")
@@ -297,9 +298,11 @@ internal abstract class SASDefaultVerificationTransaction(
             return
         }
 
-        trust(otherMasterKeyIsVerified,
+        trust(
+                otherMasterKeyIsVerified,
                 verifiedDevices,
-                eventuallyMarkMyMasterKeyAsTrusted = otherMasterKey?.trustLevel?.isVerified() == false)
+                eventuallyMarkMyMasterKeyAsTrusted = otherMasterKey?.trustLevel?.isVerified() == false
+        )
     }
 
     override fun cancel() {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SendVerificationMessageWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SendVerificationMessageWorker.kt
deleted file mode 100644
index 0a175ae3ca22a971dab0c84119fde3789b18aa60..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SendVerificationMessageWorker.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * 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 org.matrix.android.sdk.internal.crypto.verification
-
-import android.content.Context
-import androidx.work.Data
-import androidx.work.WorkerParameters
-import com.squareup.moshi.JsonClass
-import org.matrix.android.sdk.api.failure.shouldBeRetried
-import org.matrix.android.sdk.internal.SessionManager
-import org.matrix.android.sdk.internal.crypto.tasks.SendVerificationMessageTask
-import org.matrix.android.sdk.internal.session.SessionComponent
-import org.matrix.android.sdk.internal.session.room.send.CancelSendTracker
-import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository
-import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
-import org.matrix.android.sdk.internal.worker.SessionWorkerParams
-import timber.log.Timber
-import javax.inject.Inject
-
-/**
- * Possible previous worker: None
- * Possible next worker    : None
- */
-internal class SendVerificationMessageWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
-        SessionSafeCoroutineWorker<SendVerificationMessageWorker.Params>(context, params, sessionManager, Params::class.java) {
-
-    @JsonClass(generateAdapter = true)
-    internal data class Params(
-            override val sessionId: String,
-            val eventId: String,
-            override val lastFailureMessage: String? = null
-    ) : SessionWorkerParams
-
-    @Inject lateinit var sendVerificationMessageTask: SendVerificationMessageTask
-    @Inject lateinit var localEchoRepository: LocalEchoRepository
-    @Inject lateinit var cancelSendTracker: CancelSendTracker
-
-    override fun injectWith(injector: SessionComponent) {
-        injector.inject(this)
-    }
-
-    override suspend fun doSafeWork(params: Params): Result {
-        val localEvent = localEchoRepository.getUpToDateEcho(params.eventId) ?: return buildErrorResult(params, "Event not found")
-        val localEventId = localEvent.eventId ?: ""
-        val roomId = localEvent.roomId ?: ""
-
-        if (cancelSendTracker.isCancelRequestedFor(localEventId, roomId)) {
-            return Result.success()
-                    .also {
-                        cancelSendTracker.markCancelled(localEventId, roomId)
-                        Timber.e("## SendEvent: Event sending has been cancelled $localEventId")
-                    }
-        }
-
-        return try {
-            val resultEventId = sendVerificationMessageTask.execute(
-                    SendVerificationMessageTask.Params(
-                            event = localEvent
-                    )
-            )
-
-            Result.success(Data.Builder().putString(localEventId, resultEventId).build())
-        } catch (throwable: Throwable) {
-            if (throwable.shouldBeRetried()) {
-                Result.retry()
-            } else {
-                buildErrorResult(params, throwable.localizedMessage ?: "error")
-            }
-        }
-    }
-
-    override fun buildErrorParams(params: Params, message: String): Params {
-        return params.copy(lastFailureMessage = params.lastFailureMessage ?: message)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoAccept.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoAccept.kt
index 79aabba59db0dd216f18156d1e8265e5c0edb013..3ddb0ca758038f50c9520931c3890b69327702b2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoAccept.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoAccept.kt
@@ -17,28 +17,28 @@ package org.matrix.android.sdk.internal.crypto.verification
 
 internal interface VerificationInfoAccept : VerificationInfo<ValidVerificationInfoAccept> {
     /**
-     * The key agreement protocol that Bob’s device has selected to use, out of the list proposed by Alice’s device
+     * The key agreement protocol that Bob’s device has selected to use, out of the list proposed by Alice’s device.
      */
     val keyAgreementProtocol: String?
 
     /**
-     * The hash algorithm that Bob’s device has selected to use, out of the list proposed by Alice’s device
+     * The hash algorithm that Bob’s device has selected to use, out of the list proposed by Alice’s device.
      */
     val hash: String?
 
     /**
-     * The message authentication code that Bob’s device has selected to use, out of the list proposed by Alice’s device
+     * The message authentication code that Bob’s device has selected to use, out of the list proposed by Alice’s device.
      */
     val messageAuthenticationCode: String?
 
     /**
-     * An array of short authentication string methods that Bob’s client (and Bob) understands.  Must be a subset of the list proposed by Alice’s device
+     * An array of short authentication string methods that Bob’s client (and Bob) understands.  Must be a subset of the list proposed by Alice’s device.
      */
     val shortAuthenticationStrings: List<String>?
 
     /**
      * The hash (encoded as unpadded base64) of the concatenation of the device’s ephemeral public key (QB, encoded as unpadded base64)
-     *  and the canonical JSON representation of the m.key.verification.start message.
+     * and the canonical JSON representation of the m.key.verification.start message.
      */
     var commitment: String?
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoCancel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoCancel.kt
index 35c05ac05863b006176479df504dd47063ce8194..20e2cdcd33f90db975b42fea5a0ae649fcea46a8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoCancel.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoCancel.kt
@@ -17,7 +17,7 @@ package org.matrix.android.sdk.internal.crypto.verification
 
 internal interface VerificationInfoCancel : VerificationInfo<ValidVerificationInfoCancel> {
     /**
-     * machine-readable reason for cancelling, see [CancelCode]
+     * machine-readable reason for cancelling, see [CancelCode].
      */
     val code: String?
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoKey.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoKey.kt
index 23c117d8441d3d6905d6f0380a7d1d87c735fce5..2885b81a12fa2598b30f5bdceac7ab52e1ac38ce 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoKey.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoKey.kt
@@ -20,7 +20,7 @@ package org.matrix.android.sdk.internal.crypto.verification
  */
 internal interface VerificationInfoKey : VerificationInfo<ValidVerificationInfoKey> {
     /**
-     * The device’s ephemeral public key, as an unpadded base64 string
+     * The device’s ephemeral public key, as an unpadded base64 string.
      */
     val key: String?
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoMac.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoMac.kt
index 5515acc2f1eb0e473c42b5092326d65698337889..d6f1d7e4dbdbf3ddf551536b138d58cdf2cd89cd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoMac.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoMac.kt
@@ -17,7 +17,7 @@ package org.matrix.android.sdk.internal.crypto.verification
 
 internal interface VerificationInfoMac : VerificationInfo<ValidVerificationInfoMac> {
     /**
-     * A map of key ID to the MAC of the key, as an unpadded base64 string, calculated using the MAC key
+     * A map of key ID to the MAC of the key, as an unpadded base64 string, calculated using the MAC key.
      */
     val mac: Map<String, String>?
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoReady.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoReady.kt
index 327c09dabff9581f5eb21fa249e0823fd2e14b6b..2e397eee08ff113b138e165a693cb268eb2c3c28 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoReady.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoReady.kt
@@ -27,12 +27,12 @@ import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationI
 
 internal interface VerificationInfoReady : VerificationInfo<ValidVerificationInfoReady> {
     /**
-     * The ID of the device that sent the m.key.verification.ready message
+     * The ID of the device that sent the m.key.verification.ready message.
      */
     val fromDevice: String?
 
     /**
-     * An array of verification methods that the device supports
+     * An array of verification methods that the device supports.
      */
     val methods: List<String>?
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoStart.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoStart.kt
index 40c96dfa9591dc5e32fa62890060376f7e5c5230..d71bd7359ee8a5cc932f58d20a5ec0faff38e67a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoStart.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoStart.kt
@@ -24,7 +24,7 @@ internal interface VerificationInfoStart : VerificationInfo<ValidVerificationInf
     val method: String?
 
     /**
-     * Alice’s device ID
+     * Alice’s device ID.
      */
     val fromDevice: String?
 
@@ -57,7 +57,7 @@ internal interface VerificationInfoStart : VerificationInfo<ValidVerificationInf
     val shortAuthenticationStrings: List<String>?
 
     /**
-     * Shared secret, when starting verification with QR code
+     * Shared secret, when starting verification with QR code.
      */
     val sharedSecret: String?
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationMessageProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationMessageProcessor.kt
index ec4e1aa65cb58ac337f8345286ebb16723c515f6..303b6c5839ffbe23dbbd3edfd98490ed7953eee1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationMessageProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationMessageProcessor.kt
@@ -15,13 +15,9 @@
  */
 package org.matrix.android.sdk.internal.crypto.verification
 
-import io.realm.Realm
-import org.matrix.android.sdk.api.session.crypto.MXCryptoError
-import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.LocalEcho
 import org.matrix.android.sdk.api.session.events.model.toModel
 import org.matrix.android.sdk.api.session.room.model.message.MessageContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
@@ -29,22 +25,18 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageType
 import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationReadyContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationStartContent
-import org.matrix.android.sdk.internal.crypto.EventDecryptor
-import org.matrix.android.sdk.internal.database.model.EventInsertType
 import org.matrix.android.sdk.internal.di.DeviceId
 import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor
 import org.matrix.android.sdk.internal.util.time.Clock
 import timber.log.Timber
 import javax.inject.Inject
 
 internal class VerificationMessageProcessor @Inject constructor(
-        private val eventDecryptor: EventDecryptor,
-        private val clock: Clock,
         private val verificationService: DefaultVerificationService,
         @UserId private val userId: String,
-        @DeviceId private val deviceId: String?
-) : EventInsertLiveProcessor {
+        @DeviceId private val deviceId: String?,
+        private val clock: Clock,
+) {
 
     private val transactionsHandledByOtherDevice = ArrayList<String>()
 
@@ -60,40 +52,20 @@ internal class VerificationMessageProcessor @Inject constructor(
             EventType.ENCRYPTED
     )
 
-    override fun shouldProcess(eventId: String, eventType: String, insertType: EventInsertType): Boolean {
-        if (insertType != EventInsertType.INCREMENTAL_SYNC) {
-            return false
-        }
-        return allowedTypes.contains(eventType) && !LocalEcho.isLocalEchoId(eventId)
+    fun shouldProcess(eventType: String): Boolean {
+        return allowedTypes.contains(eventType)
     }
 
-    override suspend fun process(realm: Realm, event: Event) {
-        Timber.v("## SAS Verification live observer: received msgId: ${event.eventId} msgtype: ${event.type} from ${event.senderId}")
+    suspend fun process(event: Event) {
+        Timber.v("## SAS Verification live observer: received msgId: ${event.eventId} msgtype: ${event.getClearType()} from ${event.senderId}")
 
         // If the request is in the future by more than 5 minutes or more than 10 minutes in the past,
         // the message should be ignored by the receiver.
 
-        if (!VerificationService.isValidRequest(event.ageLocalTs ?: event.originServerTs, clock.epochMillis())) return Unit.also {
-            Timber.d("## SAS Verification live observer: msgId: ${event.eventId} is outdated")
+        if (event.ageLocalTs != null && !VerificationService.isValidRequest(event.ageLocalTs, clock.epochMillis())) return Unit.also {
+            Timber.d("## SAS Verification live observer: msgId: ${event.eventId} is outdated age:$event.ageLocalTs ms")
         }
 
-        // decrypt if needed?
-        if (event.isEncrypted() && event.mxDecryptionResult == null) {
-            // TODO use a global event decryptor? attache to session and that listen to new sessionId?
-            // for now decrypt sync
-            try {
-                val result = eventDecryptor.decryptEvent(event, "")
-                event.mxDecryptionResult = OlmDecryptionResult(
-                        payload = result.clearEvent,
-                        senderKey = result.senderCurve25519Key,
-                        keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
-                        forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
-                )
-            } catch (e: MXCryptoError) {
-                Timber.e("## SAS Failed to decrypt event: ${event.eventId}")
-                verificationService.onPotentiallyInterestingEventRoomFailToDecrypt(event)
-            }
-        }
         Timber.v("## SAS Verification live observer: received msgId: ${event.eventId} type: ${event.getClearType()}")
 
         // Relates to is not encrypted
@@ -102,7 +74,6 @@ internal class VerificationMessageProcessor @Inject constructor(
         if (event.senderId == userId) {
             // If it's send from me, we need to keep track of Requests or Start
             // done from another device of mine
-
             if (EventType.MESSAGE == event.getClearType()) {
                 val msgType = event.getClearContent().toModel<MessageContent>()?.msgType
                 if (MessageType.MSGTYPE_VERIFICATION_REQUEST == msgType) {
@@ -137,6 +108,8 @@ internal class VerificationMessageProcessor @Inject constructor(
                     transactionsHandledByOtherDevice.remove(it)
                     verificationService.onRoomRequestHandledByOtherDevice(event)
                 }
+            } else if (EventType.ENCRYPTED == event.getClearType()) {
+                verificationService.onPotentiallyInterestingEventRoomFailToDecrypt(event)
             }
 
             Timber.v("## SAS Verification ignoring message sent by me: ${event.eventId} type: ${event.getClearType()}")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransport.kt
index c326dd0fc30fa3d147cac81cecd1713063ba8232..c12aea9d52df4c51baab15eceddcc829cb35ea1d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransport.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransport.kt
@@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxStat
 internal interface VerificationTransport {
 
     /**
-     * Sends a message
+     * Sends a message.
      */
     fun <T> sendToOther(type: String,
                         verificationInfo: VerificationInfo<T>,
@@ -53,7 +53,7 @@ internal interface VerificationTransport {
              onDone: (() -> Unit)?)
 
     /**
-     * Creates an accept message suitable for this transport
+     * Creates an accept message suitable for this transport.
      */
     fun createAccept(tid: String,
                      keyAgreementProtocol: String,
@@ -66,7 +66,7 @@ internal interface VerificationTransport {
                   pubKey: String): VerificationInfoKey
 
     /**
-     * Create start for SAS verification
+     * Create start for SAS verification.
      */
     fun createStartForSas(fromDevice: String,
                           transactionId: String,
@@ -76,7 +76,7 @@ internal interface VerificationTransport {
                           shortAuthenticationStrings: List<String>): VerificationInfoStart
 
     /**
-     * Create start for QR code verification
+     * Create start for QR code verification.
      */
     fun createStartForQrCode(fromDevice: String,
                              transactionId: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportRoomMessage.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportRoomMessage.kt
index 325a6f0ba2daef51f2dbc5914a1bce98d31de627..e32828af23850154040aa9db82f8e738153de544 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportRoomMessage.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportRoomMessage.kt
@@ -15,14 +15,8 @@
  */
 package org.matrix.android.sdk.internal.crypto.verification
 
-import androidx.lifecycle.Observer
-import androidx.work.BackoffPolicy
-import androidx.work.Data
-import androidx.work.ExistingWorkPolicy
-import androidx.work.Operation
-import androidx.work.WorkInfo
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.asCoroutineDispatcher
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
 import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationInfoRequest
@@ -45,27 +39,28 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageVerification
 import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
 import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_RECIPROCATE
 import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_SAS
-import org.matrix.android.sdk.internal.di.WorkManagerProvider
+import org.matrix.android.sdk.internal.crypto.tasks.SendVerificationMessageTask
 import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
+import org.matrix.android.sdk.internal.task.SemaphoreCoroutineSequencer
 import org.matrix.android.sdk.internal.util.time.Clock
-import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
-import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
 import timber.log.Timber
-import java.util.UUID
-import java.util.concurrent.TimeUnit
+import java.util.concurrent.Executors
 
 internal class VerificationTransportRoomMessage(
-        private val workManagerProvider: WorkManagerProvider,
-        private val sessionId: String,
+        private val sendVerificationMessageTask: SendVerificationMessageTask,
         private val userId: String,
         private val userDeviceId: String?,
         private val roomId: String,
         private val localEchoEventFactory: LocalEchoEventFactory,
         private val tx: DefaultVerificationTransaction?,
-        private val coroutineScope: CoroutineScope,
+        cryptoCoroutineScope: CoroutineScope,
         private val clock: Clock,
 ) : VerificationTransport {
 
+    private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
+    private val verificationSenderScope = CoroutineScope(cryptoCoroutineScope.coroutineContext + dispatcher)
+    private val sequencer = SemaphoreCoroutineSequencer()
+
     override fun <T> sendToOther(type: String,
                                  verificationInfo: VerificationInfo<T>,
                                  nextState: VerificationTxState,
@@ -79,70 +74,22 @@ internal class VerificationTransportRoomMessage(
                 content = verificationInfo.toEventContent()!!
         )
 
-        val workerParams = WorkerParamsFactory.toData(
-                SendVerificationMessageWorker.Params(
-                        sessionId = sessionId,
-                        eventId = event.eventId ?: ""
-                )
-        )
-        val enqueueInfo = enqueueSendWork(workerParams)
-
-        // I cannot just listen to the given work request, because when used in a uniqueWork,
-        // The callback is called while it is still Running ...
-
-//        Futures.addCallback(enqueueInfo.first.result, object : FutureCallback<Operation.State.SUCCESS> {
-//            override fun onSuccess(result: Operation.State.SUCCESS?) {
-//                if (onDone != null) {
-//                    onDone()
-//                } else {
-//                    tx?.state = nextState
-//                }
-//            }
-//
-//            override fun onFailure(t: Throwable) {
-//                Timber.e("## SAS verification [${tx?.transactionId}] failed to send toDevice in state : ${tx?.state}, reason: ${t.localizedMessage}")
-//                tx?.cancel(onErrorReason)
-//            }
-//        }, listenerExecutor)
-
-        val workLiveData = workManagerProvider.workManager
-                .getWorkInfosForUniqueWorkLiveData(uniqueQueueName())
-
-        val observer = object : Observer<List<WorkInfo>> {
-            override fun onChanged(workInfoList: List<WorkInfo>?) {
-                workInfoList
-                        ?.firstOrNull { it.id == enqueueInfo.second }
-                        ?.let { wInfo ->
-                            when (wInfo.state) {
-                                WorkInfo.State.FAILED    -> {
-                                    tx?.cancel(onErrorReason)
-                                    workLiveData.removeObserver(this)
-                                }
-                                WorkInfo.State.SUCCEEDED -> {
-                                    if (SessionSafeCoroutineWorker.hasFailed(wInfo.outputData)) {
-                                        Timber.e("## SAS verification [${tx?.transactionId}] failed to send verification message in state : ${tx?.state}")
-                                        tx?.cancel(onErrorReason)
-                                    } else {
-                                        if (onDone != null) {
-                                            onDone()
-                                        } else {
-                                            tx?.state = nextState
-                                        }
-                                    }
-                                    workLiveData.removeObserver(this)
-                                }
-                                else                     -> {
-                                    // nop
-                                }
-                            }
-                        }
+        verificationSenderScope.launch {
+            sequencer.post {
+                try {
+                    val params = SendVerificationMessageTask.Params(event)
+                    sendVerificationMessageTask.executeRetry(params, 5)
+                    // Do I need to update local echo state to sent?
+                    if (onDone != null) {
+                        onDone()
+                    } else {
+                        tx?.state = nextState
+                    }
+                } catch (failure: Throwable) {
+                    tx?.cancel(onErrorReason)
+                }
             }
         }
-
-        // TODO listen to DB to get synced info
-        coroutineScope.launch(Dispatchers.Main) {
-            workLiveData.observeForever(observer)
-        }
     }
 
     override fun sendVerificationRequest(supportedMethods: List<String>,
@@ -173,60 +120,24 @@ internal class VerificationTransportRoomMessage(
         val content = info.toContent()
 
         val event = createEventAndLocalEcho(
-                localId,
-                EventType.MESSAGE,
-                roomId,
-                content
-        )
-
-        val workerParams = WorkerParamsFactory.toData(
-                SendVerificationMessageWorker.Params(
-                        sessionId = sessionId,
-                        eventId = event.eventId ?: ""
-                )
+                localId = localId,
+                type = EventType.MESSAGE,
+                roomId = roomId,
+                content = content
         )
 
-        val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<SendVerificationMessageWorker>()
-                .setConstraints(WorkManagerProvider.workConstraints)
-                .setInputData(workerParams)
-                .setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
-                .build()
-
-        workManagerProvider.workManager
-                .beginUniqueWork("${roomId}_VerificationWork", ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest)
-                .enqueue()
-
-        // I cannot just listen to the given work request, because when used in a uniqueWork,
-        // The callback is called while it is still Running ...
-
-        val workLiveData = workManagerProvider.workManager
-                .getWorkInfosForUniqueWorkLiveData("${roomId}_VerificationWork")
-
-        val observer = object : Observer<List<WorkInfo>> {
-            override fun onChanged(workInfoList: List<WorkInfo>?) {
-                workInfoList
-                        ?.filter { it.state == WorkInfo.State.SUCCEEDED }
-                        ?.firstOrNull { it.id == workRequest.id }
-                        ?.let { wInfo ->
-                            if (SessionSafeCoroutineWorker.hasFailed(wInfo.outputData)) {
-                                callback(null, null)
-                            } else {
-                                val eventId = wInfo.outputData.getString(localId)
-                                if (eventId != null) {
-                                    callback(eventId, validInfo)
-                                } else {
-                                    callback(null, null)
-                                }
-                            }
-                            workLiveData.removeObserver(this)
-                        }
+        verificationSenderScope.launch {
+            val params = SendVerificationMessageTask.Params(event)
+            sequencer.post {
+                try {
+                    val eventId = sendVerificationMessageTask.executeRetry(params, 5)
+                    // Do I need to update local echo state to sent?
+                    callback(eventId, validInfo)
+                } catch (failure: Throwable) {
+                    callback(null, null)
+                }
             }
         }
-
-        // TODO listen to DB to get synced info
-        coroutineScope.launch(Dispatchers.Main) {
-            workLiveData.observeForever(observer)
-        }
     }
 
     override fun cancelTransaction(transactionId: String, otherUserId: String, otherUserDeviceId: String?, code: CancelCode) {
@@ -236,13 +147,17 @@ internal class VerificationTransportRoomMessage(
                 roomId = roomId,
                 content = MessageVerificationCancelContent.create(transactionId, code).toContent()
         )
-        val workerParams = WorkerParamsFactory.toData(
-                SendVerificationMessageWorker.Params(
-                        sessionId = sessionId,
-                        eventId = event.eventId ?: ""
-                )
-        )
-        enqueueSendWork(workerParams)
+
+        verificationSenderScope.launch {
+            sequencer.post {
+                try {
+                    val params = SendVerificationMessageTask.Params(event)
+                    sendVerificationMessageTask.executeRetry(params, 5)
+                } catch (failure: Throwable) {
+                    Timber.w(failure, "Failed to cancel verification transaction")
+                }
+            }
+        }
     }
 
     override fun done(transactionId: String,
@@ -258,47 +173,21 @@ internal class VerificationTransportRoomMessage(
                         )
                 ).toContent()
         )
-        val workerParams = WorkerParamsFactory.toData(
-                SendVerificationMessageWorker.Params(
-                        sessionId = sessionId,
-                        eventId = event.eventId ?: ""
-                )
-        )
-        val enqueueInfo = enqueueSendWork(workerParams)
-
-        val workLiveData = workManagerProvider.workManager
-                .getWorkInfosForUniqueWorkLiveData(uniqueQueueName())
-        val observer = object : Observer<List<WorkInfo>> {
-            override fun onChanged(workInfoList: List<WorkInfo>?) {
-                workInfoList
-                        ?.filter { it.state == WorkInfo.State.SUCCEEDED }
-                        ?.firstOrNull { it.id == enqueueInfo.second }
-                        ?.let { _ ->
-                            onDone?.invoke()
-                            workLiveData.removeObserver(this)
-                        }
+        verificationSenderScope.launch {
+            sequencer.post {
+                try {
+                    val params = SendVerificationMessageTask.Params(event)
+                    sendVerificationMessageTask.executeRetry(params, 5)
+                } catch (failure: Throwable) {
+                    Timber.w(failure, "Failed to complete (done) verification")
+                    // should we call onDone?
+                } finally {
+                    onDone?.invoke()
+                }
             }
         }
-
-        // TODO listen to DB to get synced info
-        coroutineScope.launch(Dispatchers.Main) {
-            workLiveData.observeForever(observer)
-        }
     }
 
-    private fun enqueueSendWork(workerParams: Data): Pair<Operation, UUID> {
-        val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<SendVerificationMessageWorker>()
-                .setConstraints(WorkManagerProvider.workConstraints)
-                .setInputData(workerParams)
-                .setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
-                .build()
-        return workManagerProvider.workManager
-                .beginUniqueWork(uniqueQueueName(), ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest)
-                .enqueue() to workRequest.id
-    }
-
-    private fun uniqueQueueName() = "${roomId}_VerificationWork"
-
     override fun createAccept(tid: String,
                               keyAgreementProtocol: String,
                               hash: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportRoomMessageFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportRoomMessageFactory.kt
index b1b7ad7a98eb34cbf85ff214e5cef255d271ec2b..345948e6087b94fab6e3df857e57354a10962048 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportRoomMessageFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportRoomMessageFactory.kt
@@ -16,39 +16,35 @@
 
 package org.matrix.android.sdk.internal.crypto.verification
 
+import kotlinx.coroutines.CoroutineScope
+import org.matrix.android.sdk.internal.crypto.tasks.SendVerificationMessageTask
 import org.matrix.android.sdk.internal.di.DeviceId
-import org.matrix.android.sdk.internal.di.SessionId
 import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.di.WorkManagerProvider
 import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
-import org.matrix.android.sdk.internal.task.TaskExecutor
 import org.matrix.android.sdk.internal.util.time.Clock
 import javax.inject.Inject
 
 internal class VerificationTransportRoomMessageFactory @Inject constructor(
-        private val workManagerProvider: WorkManagerProvider,
-        @SessionId
-        private val sessionId: String,
+        private val sendVerificationMessageTask: SendVerificationMessageTask,
         @UserId
         private val userId: String,
         @DeviceId
         private val deviceId: String?,
         private val localEchoEventFactory: LocalEchoEventFactory,
-        private val taskExecutor: TaskExecutor,
+        private val cryptoCoroutineScope: CoroutineScope,
         private val clock: Clock,
 ) {
 
     fun createTransport(roomId: String, tx: DefaultVerificationTransaction?): VerificationTransportRoomMessage {
         return VerificationTransportRoomMessage(
-                workManagerProvider,
-                sessionId,
-                userId,
-                deviceId,
-                roomId,
-                localEchoEventFactory,
-                tx,
-                taskExecutor.executorScope,
-                clock
+                sendVerificationMessageTask = sendVerificationMessageTask,
+                userId = userId,
+                userDeviceId = deviceId,
+                roomId = roomId,
+                localEchoEventFactory = localEchoEventFactory,
+                tx = tx,
+                cryptoCoroutineScope = cryptoCoroutineScope,
+                clock = clock,
         )
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt
index 06f0b367980a26838f0d853b58028bb5b352911b..b1ad4d87b6a56acec89926cb826b7692ea48e96d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt
@@ -22,8 +22,8 @@ import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerification
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.util.fromBase64
-import org.matrix.android.sdk.internal.crypto.IncomingGossipingRequestManager
-import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager
+import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
+import org.matrix.android.sdk.internal.crypto.SecretShareManager
 import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
 import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64Safe
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
@@ -37,8 +37,8 @@ internal class DefaultQrCodeVerificationTransaction(
         override val otherUserId: String,
         override var otherDeviceId: String?,
         private val crossSigningService: CrossSigningService,
-        outgoingGossipingRequestManager: OutgoingGossipingRequestManager,
-        incomingGossipingRequestManager: IncomingGossipingRequestManager,
+        outgoingKeyRequestManager: OutgoingKeyRequestManager,
+        secretShareManager: SecretShareManager,
         private val cryptoStore: IMXCryptoStore,
         // Not null only if other user is able to scan QR code
         private val qrCodeData: QrCodeData?,
@@ -48,13 +48,14 @@ internal class DefaultQrCodeVerificationTransaction(
 ) : DefaultVerificationTransaction(
         setDeviceVerificationAction,
         crossSigningService,
-        outgoingGossipingRequestManager,
-        incomingGossipingRequestManager,
+        outgoingKeyRequestManager,
+        secretShareManager,
         userId,
         transactionId,
         otherUserId,
         otherDeviceId,
-        isIncoming),
+        isIncoming
+),
         QrCodeVerificationTransaction {
 
     override val qrCodeText: String?
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeData.kt
index 0ac57db9bc779bc11b5bf9267b94f0856c7fb0a6..f308807e0432bd845fb2475404d72ec303b6227d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/QrCodeData.kt
@@ -21,34 +21,34 @@ package org.matrix.android.sdk.internal.crypto.verification.qrcode
  */
 internal sealed class QrCodeData(
         /**
-         * the event ID or transaction_id of the associated verification
+         * the event ID or transaction_id of the associated verification.
          */
         open val transactionId: String,
         /**
-         * First key (32 bytes, in base64 no padding)
+         * First key (32 bytes, in base64 no padding).
          */
         val firstKey: String,
         /**
-         * Second key (32 bytes, in base64 no padding)
+         * Second key (32 bytes, in base64 no padding).
          */
         val secondKey: String,
         /**
-         * a random shared secret (in base64 no padding)
+         * a random shared secret (in base64 no padding).
          */
         open val sharedSecret: String
 ) {
     /**
-     * verifying another user with cross-signing
-     * QR code verification mode: 0x00
+     * Verifying another user with cross-signing
+     * QR code verification mode: 0x00.
      */
     data class VerifyingAnotherUser(
             override val transactionId: String,
             /**
-             * the user's own master cross-signing public key
+             * the user's own master cross-signing public key.
              */
             val userMasterCrossSigningPublicKey: String,
             /**
-             * what the device thinks the other user's master cross-signing key is
+             * what the device thinks the other user's master cross-signing key is.
              */
             val otherUserMasterCrossSigningPublicKey: String,
             override val sharedSecret: String
@@ -56,20 +56,21 @@ internal sealed class QrCodeData(
             transactionId,
             userMasterCrossSigningPublicKey,
             otherUserMasterCrossSigningPublicKey,
-            sharedSecret)
+            sharedSecret
+    )
 
     /**
      * self-verifying in which the current device does trust the master key
-     * QR code verification mode: 0x01
+     * QR code verification mode: 0x01.
      */
     data class SelfVerifyingMasterKeyTrusted(
             override val transactionId: String,
             /**
-             * the user's own master cross-signing public key
+             * the user's own master cross-signing public key.
              */
             val userMasterCrossSigningPublicKey: String,
             /**
-             * what the device thinks the other device's device key is
+             * what the device thinks the other device's device key is.
              */
             val otherDeviceKey: String,
             override val sharedSecret: String
@@ -77,20 +78,21 @@ internal sealed class QrCodeData(
             transactionId,
             userMasterCrossSigningPublicKey,
             otherDeviceKey,
-            sharedSecret)
+            sharedSecret
+    )
 
     /**
      * self-verifying in which the current device does not yet trust the master key
-     * QR code verification mode: 0x02
+     * QR code verification mode: 0x02.
      */
     data class SelfVerifyingMasterKeyNotTrusted(
             override val transactionId: String,
             /**
-             * the current device's device key
+             * the current device's device key.
              */
             val deviceKey: String,
             /**
-             * what the device thinks the user's master cross-signing key is
+             * what the device thinks the user's master cross-signing key is.
              */
             val userMasterCrossSigningPublicKey: String,
             override val sharedSecret: String
@@ -98,5 +100,6 @@ internal sealed class QrCodeData(
             transactionId,
             deviceKey,
             userMasterCrossSigningPublicKey,
-            sharedSecret)
+            sharedSecret
+    )
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt
index 7c622146d34682e41469f77227160ed98b42dd9e..392c1a7185a98df3ac69dc0af04faae422df5570 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt
@@ -53,7 +53,7 @@ internal class RealmKeysUtils @Inject constructor(context: Context,
     }
 
     /**
-     * Check if there is already a key for this alias
+     * Check if there is already a key for this alias.
      */
     private fun hasKeyForDatabase(alias: String): Boolean {
         return sharedPreferences.contains("${ENCRYPTED_KEY_PREFIX}_$alias")
@@ -77,8 +77,8 @@ internal class RealmKeysUtils @Inject constructor(context: Context,
     }
 
     /**
-     * Retrieves the key for this database
-     * throws if something goes wrong
+     * Retrieves the key for this database.
+     * Throws if something goes wrong.
      */
     private fun extractKeyForDatabase(alias: String): ByteArray {
         val encryptedB64 = sharedPreferences.getString("${ENCRYPTED_KEY_PREFIX}_$alias", null)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt
index 04a6e83ea17723fee7b5a6ff7aa8efaf9f12e31a..55bccfd1ec69775d60c2d951cab7fe37a5dad786 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt
@@ -54,8 +54,8 @@ internal class RealmSessionStoreMigration @Inject constructor(
         private val normalizer: Normalizer
 ) : RealmMigration {
     /**
-     * Forces all RealmSessionStoreMigration instances to be equal
-     * Avoids Realm throwing when multiple instances of the migration are set
+     * Forces all RealmSessionStoreMigration instances to be equal.
+     * Avoids Realm throwing when multiple instances of the migration are set.
      */
     override fun equals(other: Any?) = other is RealmSessionStoreMigration
     override fun hashCode() = 1000
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt
index 4fdedabd705dc5223aef54e91c19c00d0a721a71..caaf6b81100ce609bf37c09213522768f77db7b8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt
@@ -166,7 +166,7 @@ private fun ChunkEntity.addTimelineEventFromMerge(realm: Realm, timelineEventEnt
 }
 
 /**
- * Upon copy of the timeline events we should update the latestMessage TimelineEventEntity with the new one
+ * Upon copy of the timeline events we should update the latestMessage TimelineEventEntity with the new one.
  */
 private fun handleThreadSummary(realm: Realm, oldEventId: String, newTimelineEventEntity: TimelineEventEntity) {
     EventEntity
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadEventsHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadEventsHelper.kt
index 04cf5b78af79e8dc4d3994782ac11768d6a55580..db3647c3fae24312b899091329e4a7c4b7aea074 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadEventsHelper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadEventsHelper.kt
@@ -83,7 +83,7 @@ internal fun EventEntity.findRootThreadEvent(): EventEntity? =
         }
 
 /**
- * Mark or update the current event a root thread event
+ * Mark or update the current event a root thread event.
  */
 internal fun EventEntity.markEventAsRoot(
         inThreadMessages: Int,
@@ -94,8 +94,8 @@ internal fun EventEntity.markEventAsRoot(
 }
 
 /**
- * Count the number of threads for the provided root thread eventId, and finds the latest event message
- * note: Redactions are handled by RedactionEventProcessor
+ * Count the number of threads for the provided root thread eventId, and finds the latest event message.
+ * Note: Redactions are handled by RedactionEventProcessor.
  * @param rootThreadEventId The root eventId that will find the number of threads
  * @return A ThreadSummary containing the counted threads and the latest event message
  */
@@ -150,7 +150,7 @@ internal fun countInThreadMessages(realm: Realm, roomId: String, rootThreadEvent
                 }.size
 
 /**
- * Mapping string to UnsignedData using Moshi
+ * Mapping string to UnsignedData using Moshi.
  */
 private fun String.toUnsignedData(): UnsignedData? =
         try {
@@ -162,7 +162,7 @@ private fun String.toUnsignedData(): UnsignedData? =
 
 /**
  * Lets compare them in case user is moving forward in the timeline and we cannot know the
- * exact chunk sequence while currentChunk is not yet committed in the DB
+ * exact chunk sequence while currentChunk is not yet committed in the DB.
  */
 private fun findMostRecentEvent(result: TimelineEventEntity, currentChunkLatestEvent: TimelineEventEntity?): TimelineEventEntity {
     currentChunkLatestEvent ?: return result
@@ -175,7 +175,7 @@ private fun findMostRecentEvent(result: TimelineEventEntity, currentChunkLatestE
 }
 
 /**
- * Find the latest event of the current chunk
+ * Find the latest event of the current chunk.
  */
 private fun findLatestSortedChunkEvent(chunk: ChunkEntity, rootThreadEventId: String): TimelineEventEntity? =
         chunk.timelineEvents.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)?.firstOrNull {
@@ -183,7 +183,7 @@ private fun findLatestSortedChunkEvent(chunk: ChunkEntity, rootThreadEventId: St
         }
 
 /**
- * Find all TimelineEventEntity that are root threads for the specified room
+ * Find all TimelineEventEntity that are root threads for the specified room.
  * @param roomId The room that all stored root threads will be returned
  */
 internal fun TimelineEventEntity.Companion.findAllThreadsForRoomId(realm: Realm, roomId: String): RealmQuery<TimelineEventEntity> =
@@ -194,7 +194,7 @@ internal fun TimelineEventEntity.Companion.findAllThreadsForRoomId(realm: Realm,
                 .sort("${TimelineEventEntityFields.ROOT.THREAD_SUMMARY_LATEST_MESSAGE}.${TimelineEventEntityFields.ROOT.ORIGIN_SERVER_TS}", Sort.DESCENDING)
 
 /**
- * Map each root thread TimelineEvent with the equivalent decrypted text edition/replacement
+ * Map each root thread TimelineEvent with the equivalent decrypted text edition/replacement.
  */
 internal fun List<TimelineEvent>.mapEventsWithEdition(realm: Realm, roomId: String): List<TimelineEvent> =
         this.map {
@@ -207,15 +207,17 @@ internal fun List<TimelineEvent>.mapEventsWithEdition(realm: Realm, roomId: Stri
                     ?.eventId
                     ?.let { editedEventId ->
                         TimelineEventEntity.where(realm, roomId, eventId = editedEventId).findFirst()?.let { editedEvent ->
-                            it.root.threadDetails = it.root.threadDetails?.copy(lastRootThreadEdition = editedEvent.root?.asDomain()?.getDecryptedTextSummary()
-                                    ?: "(edited)")
+                            it.root.threadDetails = it.root.threadDetails?.copy(
+                                    lastRootThreadEdition = editedEvent.root?.asDomain()?.getDecryptedTextSummary()
+                                            ?: "(edited)"
+                            )
                             it
                         } ?: it
                     } ?: it
         }
 
 /**
- * Returns a list of all the marked unread threads that exists for the specified room
+ * Returns a list of all the marked unread threads that exists for the specified room.
  * @param roomId The roomId that the user is currently in
  */
 internal fun TimelineEventEntity.Companion.findAllLocalThreadNotificationsForRoomId(realm: Realm, roomId: String): RealmQuery<TimelineEventEntity> =
@@ -229,7 +231,7 @@ internal fun TimelineEventEntity.Companion.findAllLocalThreadNotificationsForRoo
                 .endGroup()
 
 /**
- * Returns whether or not the given user is participating in a current thread
+ * Returns whether or not the given user is participating in a current thread.
  * @param roomId the room that the thread exists
  * @param rootThreadEventId the thread that the search will be done
  * @param senderId the user that will try to find participation
@@ -244,7 +246,7 @@ internal fun TimelineEventEntity.Companion.isUserParticipatingInThread(realm: Re
                 ?: false
 
 /**
- * Returns whether or not the given user is mentioned in a current thread
+ * Returns whether or not the given user is mentioned in a current thread.
  * @param roomId the room that the thread exists
  * @param rootThreadEventId the thread that the search will be done
  * @param userId the user that will try to find if there is a mention
@@ -260,7 +262,7 @@ internal fun TimelineEventEntity.Companion.isUserMentionedInThread(realm: Realm,
                 ?: false
 
 /**
- * Find the read receipt for the current user
+ * Find the read receipt for the current user.
  */
 internal fun findMyReadReceipt(realm: Realm, roomId: String, userId: String): String? =
         ReadReceiptEntity.where(realm, roomId = roomId, userId = userId)
@@ -268,7 +270,7 @@ internal fun findMyReadReceipt(realm: Realm, roomId: String, userId: String): St
                 ?.eventId
 
 /**
- * Returns whether or not the user is mentioned in the event
+ * Returns whether or not the user is mentioned in the event.
  */
 internal fun isUserMentioned(currentUserId: String, timelineEventEntity: TimelineEventEntity?): Boolean {
     return timelineEventEntity?.root?.asDomain()?.isUserMentioned(currentUserId) == true
@@ -341,7 +343,8 @@ internal fun updateNotificationsNew(roomId: String, realm: Realm, currentUserId:
                     realm = realm,
                     roomId = roomId,
                     rootThreadEventId = eventId,
-                    senderId = currentUserId)
+                    senderId = currentUserId
+            )
             val rootThreadEventEntity = EventEntity.where(realm, eventId).findFirst()
 
             if (isUserParticipating) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt
index d052a7dea497660a8dd83bb7ff9a530d4bf44351..3bf574c207db20f12d2949e2398426834e39b704 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt
@@ -65,7 +65,7 @@ internal fun ThreadSummaryEntity.updateThreadSummary(
 }
 
 /**
- * Updates the root thread event properties
+ * Updates the root thread event properties.
  */
 internal fun ThreadSummaryEntity.updateThreadSummaryRootEvent(
         rootThreadEventEntity: EventEntity,
@@ -84,7 +84,7 @@ internal fun ThreadSummaryEntity.updateThreadSummaryRootEvent(
 }
 
 /**
- * Updates the latest thread event properties
+ * Updates the latest thread event properties.
  */
 internal fun ThreadSummaryEntity.updateThreadSummaryLatestEvent(
         latestThreadEventEntity: EventEntity?,
@@ -241,7 +241,7 @@ private fun decryptIfNeeded(cryptoService: CryptoService?, eventEntity: EventEnt
 }
 
 /**
- * Request decryption
+ * Request decryption.
  */
 private fun requestDecryption(eventDecryptor: TimelineEventDecryptor?, event: Event?) {
     eventDecryptor ?: return
@@ -255,7 +255,7 @@ private fun requestDecryption(eventDecryptor: TimelineEventDecryptor?, event: Ev
 }
 
 /**
- * If we don't have any new state on this user, get it from db
+ * If we don't have any new state on this user, get it from db.
  */
 private fun HashMap<String, RoomMemberContent?>.addSenderState(realm: Realm, roomId: String, senderId: String) {
     getOrPut(senderId) {
@@ -267,7 +267,7 @@ private fun HashMap<String, RoomMemberContent?>.addSenderState(realm: Realm, roo
 }
 
 /**
- * Create an EventEntity for the root thread event or get an existing one
+ * Create an EventEntity for the root thread event or get an existing one.
  */
 private fun createEventEntity(realm: Realm, roomId: String, event: Event, currentTimeMillis: Long): EventEntity {
     val ageLocalTs = event.unsignedData?.age?.let { currentTimeMillis - it }
@@ -294,15 +294,15 @@ private fun createLatestEventEntity(
 }
 
 /**
- * Returned the latest event message, if any
+ * Returned the latest event message, if any.
  */
 private fun getLatestEvent(rootThreadEvent: Event): Event? {
     return rootThreadEvent.unsignedData?.relations?.latestThread?.event
 }
 
 /**
- * Find all ThreadSummaryEntity for the specified roomId, sorted by origin server
- * note: Sorting cannot be provided by server, so we have to use that unstable property
+ * Find all ThreadSummaryEntity for the specified roomId, sorted by origin server.
+ * note: Sorting cannot be provided by server, so we have to use that unstable property.
  * @param roomId The id of the room
  */
 internal fun ThreadSummaryEntity.Companion.findAllThreadsForRoomId(realm: Realm, roomId: String): RealmQuery<ThreadSummaryEntity> =
@@ -311,7 +311,7 @@ internal fun ThreadSummaryEntity.Companion.findAllThreadsForRoomId(realm: Realm,
                 .sort(ThreadSummaryEntityFields.LATEST_THREAD_EVENT_ENTITY.ORIGIN_SERVER_TS, Sort.DESCENDING)
 
 /**
- * Enhance each [ThreadSummary] root and latest event with the equivalent decrypted text edition/replacement
+ * Enhance each [ThreadSummary] root and latest event with the equivalent decrypted text edition/replacement.
  */
 internal fun List<ThreadSummary>.enhanceWithEditions(realm: Realm, roomId: String): List<ThreadSummary> =
         this.map {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/DraftMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/DraftMapper.kt
index 737c4b4608d1f206fc30c6d3fbfc5ede77cbcb5f..a00a2a8ee111d189741323704b23a465d0d2abd7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/DraftMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/DraftMapper.kt
@@ -20,7 +20,7 @@ import org.matrix.android.sdk.api.session.room.send.UserDraft
 import org.matrix.android.sdk.internal.database.model.DraftEntity
 
 /**
- * DraftEntity <-> UserDraft
+ * DraftEntity <-> UserDraft.
  */
 internal object DraftMapper {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt
index 2e33988a22b853f941add399e3da3464928e2417..20af43530c4821a11892dc1fd8d37c8dbb1a5da3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt
@@ -28,7 +28,7 @@ import org.matrix.android.sdk.internal.session.homeserver.RoomVersions
 import org.matrix.android.sdk.internal.session.room.version.DefaultRoomVersionService
 
 /**
- * HomeServerCapabilitiesEntity -> HomeSeverCapabilities
+ * HomeServerCapabilitiesEntity -> HomeSeverCapabilities.
  */
 internal object HomeServerCapabilitiesMapper {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo026.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo026.kt
index 35a6135ba203aac3f2f1a7e75543821eb9ea49db..5bab93cb04fee37ac127f93f85ff3b04e3a15866 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo026.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo026.kt
@@ -29,7 +29,7 @@ import org.matrix.android.sdk.internal.util.database.RealmMigrator
 /**
  * Migrating to:
  * Live thread list: using enhanced /messages api MSC3440
- * Live thread timeline: using /relations api
+ * Live thread timeline: using /relations api.
  */
 internal class MigrateSessionTo026(realm: DynamicRealm) : RealmMigrator(realm, 26) {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo027.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo027.kt
index fdd8c46d027ae4b4f6654e6d5799df1d3c7e115e..40189c0f466aecc10e3d3c9d2476ec01f346ba87 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo027.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo027.kt
@@ -24,7 +24,7 @@ import org.matrix.android.sdk.internal.util.database.RealmMigrator
 
 /**
  * Migrating to:
- * Live location sharing aggregated summary
+ * Live location sharing aggregated summary.
  */
 internal class MigrateSessionTo027(realm: DynamicRealm) : RealmMigrator(realm, 27) {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo028.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo028.kt
index 1d0c638d7b8fc902a4ea192aebbb6dcc6b8e6b98..ed9b90d28886a7d62e9ad5290a62d1407f36c006 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo028.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo028.kt
@@ -22,7 +22,7 @@ import org.matrix.android.sdk.internal.util.database.RealmMigrator
 
 /**
  * Migrating to:
- * Live location sharing aggregated summary
+ * Live location sharing aggregated summary.
  */
 internal class MigrateSessionTo028(realm: DynamicRealm) : RealmMigrator(realm, 28) {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ChunkEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ChunkEntity.kt
index 822bc1bd8f45c9e5f0326a61371b2e073af4354d..8399d82d5d75821e55d769dd8c8d06baca2be775 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ChunkEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ChunkEntity.kt
@@ -69,7 +69,7 @@ internal fun ChunkEntity.deleteOnCascade(
 }
 
 /**
- * Delete the chunk along with the thread events that were temporarily created
+ * Delete the chunk along with the thread events that were temporarily created.
  */
 internal fun ChunkEntity.deleteAndClearThreadEvents() {
     assertIsManaged()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EditAggregatedSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EditAggregatedSummaryEntity.kt
index 0ed927a6b8618c64cb9655956e395e5cd2be9eb9..61acd51dd46730a9e45d6a8f1bf8b3180dc7757a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EditAggregatedSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EditAggregatedSummaryEntity.kt
@@ -20,7 +20,7 @@ import io.realm.RealmObject
 import io.realm.annotations.RealmClass
 
 /**
- * Keep all the editions of a message
+ * Keep all the editions of a message.
  */
 internal open class EditAggregatedSummaryEntity(
         // The list of the editions used to build the summary (might be out of sync if chunked received from message chunk)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt
index c3abd8b028b92a211607f5bb116cd15332835c16..645998d0c029ce5b5a0ba58aaa5e95bc67efea4b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt
@@ -33,7 +33,7 @@ internal open class EventAnnotationsSummaryEntity(
 ) : RealmObject() {
 
     /**
-     * Cleanup undesired editions, done by users different from the originalEventSender
+     * Cleanup undesired editions, done by users different from the originalEventSender.
      */
     fun cleanUp(originalEventSenderId: String?) {
         originalEventSenderId ?: return
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/FilterEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/FilterEntity.kt
index 96014d29add8c720a7a6b3b98cccbe5b95a08d85..e138e305c7e6a12430b2963e9b7662a66c57f302 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/FilterEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/FilterEntity.kt
@@ -19,8 +19,8 @@ package org.matrix.android.sdk.internal.database.model
 import io.realm.RealmObject
 
 /**
- * Contain a map between Json filter string and filterId (from Homeserver)
- * Currently there is only one object in this table
+ * Contain a map between Json filter string and filterId (from Homeserver).
+ * Currently there is only one object in this table.
  */
 internal open class FilterEntity(
         // The serialized FilterBody
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PendingThreePidEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PendingThreePidEntity.kt
index 98c38c8969fa300f94c7553d55b54e69ced8a1fa..bcf64e0da8f89f0bd9841856a73d5aab8944aa8d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PendingThreePidEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PendingThreePidEntity.kt
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.database.model
 import io.realm.RealmObject
 
 /**
- * This class is used to store pending threePid data, when user wants to add a threePid to his account
+ * This class is used to store pending threePid data, when user wants to add a threePid to his account.
  */
 internal open class PendingThreePidEntity(
         var email: String? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PollResponseAggregatedSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PollResponseAggregatedSummaryEntity.kt
index 0000a558ac99349bbe682843f5489b8be273bb8e..d759bd3cd930fe5b2b3b649aba4cb419cd3ec3e4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PollResponseAggregatedSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PollResponseAggregatedSummaryEntity.kt
@@ -19,7 +19,7 @@ import io.realm.RealmList
 import io.realm.RealmObject
 
 /**
- * Keep the latest state of a poll
+ * Keep the latest state of a poll.
  */
 internal open class PollResponseAggregatedSummaryEntity(
         // For now we persist this a JSON for greater flexibility
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt
index 9a92b145101f0da1adf7a83c37447dea783b8c64..890c2300f8bd52852e64b439a424caa5353399d9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt
@@ -22,9 +22,10 @@ import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntit
 import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity
 
 /**
- * Realm module for Session
+ * Realm module for Session.
  */
-@RealmModule(library = true,
+@RealmModule(
+        library = true,
         classes = [
             ChunkEntity::class,
             EventEntity::class,
@@ -71,5 +72,6 @@ import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntit
             SpaceParentSummaryEntity::class,
             UserPresenceEntity::class,
             ThreadSummaryEntity::class
-        ])
+        ]
+)
 internal class SessionRealmModule
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserDraftsEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserDraftsEntity.kt
index 06a6349350454aaf83072cf77f62a624721d10d2..2c778f979762a31ca76788697bf1ff14a9d83d0f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserDraftsEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserDraftsEntity.kt
@@ -22,7 +22,7 @@ import io.realm.RealmResults
 import io.realm.annotations.LinkingObjects
 
 /**
- * Create a specific table to be able to do direct query on it and keep the draft ordered
+ * Create a specific table to be able to do direct query on it and keep the draft ordered.
  */
 internal open class UserDraftsEntity(var userDrafts: RealmList<DraftEntity> = RealmList()
 ) : RealmObject() {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt
index 1376839f9375d0ce7ee5c1507e552492d4fd07f6..4d0d2c5c64303cbbfc676c3ce419b3adcdc9e739 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt
@@ -36,7 +36,7 @@ internal open class LiveLocationShareAggregatedSummaryEntity(
         var endOfLiveTimestampMillis: Long? = null,
 
         /**
-         * For now we persist this as a JSON for greater flexibility
+         * For now we persist this as a JSON for greater flexibility.
          * @see [org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent]
          */
         var lastLocationContent: String? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/FilterEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/FilterEntityQueries.kt
index 3968169e08323aaeee6aebf867b5cc477eeaed26..903282bac4598c9e1f3269d364ccc772e4f78dc9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/FilterEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/FilterEntityQueries.kt
@@ -23,14 +23,14 @@ import org.matrix.android.sdk.internal.database.model.FilterEntity
 import org.matrix.android.sdk.internal.session.filter.FilterFactory
 
 /**
- * Get the current filter
+ * Get the current filter.
  */
 internal fun FilterEntity.Companion.get(realm: Realm): FilterEntity? {
     return realm.where<FilterEntity>().findFirst()
 }
 
 /**
- * Get the current filter, create one if it does not exist
+ * Get the current filter, create one if it does not exist.
  */
 internal fun FilterEntity.Companion.getOrCreate(realm: Realm): FilterEntity {
     return get(realm) ?: realm.createObject<FilterEntity>()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/HomeServerCapabilitiesQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/HomeServerCapabilitiesQueries.kt
index 4f8ac20e9446b8a057fd70d152c46059c6304a41..2cb6faafb7689f070f41c2a108b0103876edfc22 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/HomeServerCapabilitiesQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/HomeServerCapabilitiesQueries.kt
@@ -22,14 +22,14 @@ import io.realm.kotlin.where
 import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
 
 /**
- * Get the current HomeServerCapabilitiesEntity, return null if it does not exist
+ * Get the current HomeServerCapabilitiesEntity, return null if it does not exist.
  */
 internal fun HomeServerCapabilitiesEntity.Companion.get(realm: Realm): HomeServerCapabilitiesEntity? {
     return realm.where<HomeServerCapabilitiesEntity>().findFirst()
 }
 
 /**
- * Get the current HomeServerCapabilitiesEntity, create one if it does not exist
+ * Get the current HomeServerCapabilitiesEntity, create one if it does not exist.
  */
 internal fun HomeServerCapabilitiesEntity.Companion.getOrCreate(realm: Realm): HomeServerCapabilitiesEntity {
     return get(realm) ?: realm.createObject()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PreviewUrlCacheEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PreviewUrlCacheEntityQueries.kt
index a139c174394b7e3e430f89443efb7020898e730d..32ea7a1ba6d3ecb648484fa13af6440916cd2a14 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PreviewUrlCacheEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PreviewUrlCacheEntityQueries.kt
@@ -23,7 +23,7 @@ import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntity
 import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntityFields
 
 /**
- * Get the current PreviewUrlCacheEntity, return null if it does not exist
+ * Get the current PreviewUrlCacheEntity, return null if it does not exist.
  */
 internal fun PreviewUrlCacheEntity.Companion.get(realm: Realm, url: String): PreviewUrlCacheEntity? {
     return realm.where<PreviewUrlCacheEntity>()
@@ -32,7 +32,7 @@ internal fun PreviewUrlCacheEntity.Companion.get(realm: Realm, url: String): Pre
 }
 
 /**
- * Get the current PreviewUrlCacheEntity, create one if it does not exist
+ * Get the current PreviewUrlCacheEntity, create one if it does not exist.
  */
 internal fun PreviewUrlCacheEntity.Companion.getOrCreate(realm: Realm, url: String): PreviewUrlCacheEntity {
     return get(realm, url) ?: realm.createObject(url)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RawCacheQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RawCacheQueries.kt
index ac5e29e1de8e170e09712afd105904ab202c8b08..634c3b26f26e572df7e9d8010912f531581979c8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RawCacheQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RawCacheQueries.kt
@@ -23,7 +23,7 @@ import org.matrix.android.sdk.internal.database.model.RawCacheEntity
 import org.matrix.android.sdk.internal.database.model.RawCacheEntityFields
 
 /**
- * Get the current RawCacheEntity, return null if it does not exist
+ * Get the current RawCacheEntity, return null if it does not exist.
  */
 internal fun RawCacheEntity.Companion.get(realm: Realm, url: String): RawCacheEntity? {
     return realm.where<RawCacheEntity>()
@@ -32,7 +32,7 @@ internal fun RawCacheEntity.Companion.get(realm: Realm, url: String): RawCacheEn
 }
 
 /**
- * Get the current RawCacheEntity, create one if it does not exist
+ * Get the current RawCacheEntity, create one if it does not exist.
  */
 internal fun RawCacheEntity.Companion.getOrCreate(realm: Realm, url: String): RawCacheEntity {
     return get(realm, url) ?: realm.createObject(url)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt
index 6c587dfcae8381743c97383a8b7fefd64ea0115e..1a832a29bbbca135aa680e7b7e3d99a925d27266 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt
@@ -61,7 +61,7 @@ private fun TimelineEventEntity.isBeforeLatestReadReceipt(realm: Realm, roomId:
 
 /**
  * Missing events can be caused by the latest timeline chunk no longer contain an older event or
- * by fast lane eagerly displaying events before the database has finished updating
+ * by fast lane eagerly displaying events before the database has finished updating.
  */
 private fun hasReadMissingEvent(realm: Realm, latestChunkEntity: ChunkEntity, roomId: String, userId: String, eventId: String): Boolean {
     return realm.doesEventExistInChunkHistory(eventId) && realm.hasReadReceiptInLatestChunk(latestChunkEntity, roomId, userId)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt
index 215ab34f95438a7c697f5b7f48274e4e4920bdb0..1654a33806dee20f2bf1f4bfa8c342f3fdd457b5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt
@@ -143,7 +143,7 @@ internal fun RealmQuery<TimelineEventEntity>.filterSendStates(sendStates: List<S
 }
 
 /**
- * Find all TimelineEventEntity items where sender is in senderIds collection, excluding state events
+ * Find all TimelineEventEntity items where sender is in senderIds collection, excluding state events.
  */
 internal fun TimelineEventEntity.Companion.findAllFrom(realm: Realm,
                                                        senderIds: Collection<String>): RealmResults<TimelineEventEntity> {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventFilter.kt
index a7317506a0aafbf7e3d05eafb0f2dd1f365d85a0..7a65623b76fad182f58a02385462ff33a008dacc 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventFilter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventFilter.kt
@@ -17,11 +17,11 @@
 package org.matrix.android.sdk.internal.database.query
 
 /**
- * Query strings used to filter the timeline events regarding the Json raw string of the Event
+ * Query strings used to filter the timeline events regarding the Json raw string of the Event.
  */
 internal object TimelineEventFilter {
     /**
-     * To apply to Event.content
+     * To apply to Event.content.
      */
     internal object Content {
         internal const val EDIT = """{*"m.relates_to"*"rel_type":*"m.replace"*}"""
@@ -30,14 +30,14 @@ internal object TimelineEventFilter {
     }
 
     /**
-     * To apply to Event.decryptionResultJson
+     * To apply to Event.decryptionResultJson.
      */
     internal object DecryptedContent {
         internal const val URL = """{*"file":*"url":*}"""
     }
 
     /**
-     * To apply to Event.unsigned
+     * To apply to Event.unsigned.
      */
     internal object Unsigned {
         internal const val REDACTED = """{*"redacted_because":*}"""
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt
index 103e84dea6c91d7b5ff6cb1ff85093a6d600f44e..dc20549eb3e7da3aed0e8623596ea6a956045614 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/tools/RealmDebugTools.kt
@@ -25,7 +25,7 @@ internal class RealmDebugTools(
         private val realmConfiguration: RealmConfiguration
 ) {
     /**
-     * Log info about the DB
+     * Log info about the DB.
      */
     fun logInfo(baseName: String) {
         buildString {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt
index 2fad2d8e786153b3c9704fe686b26c91aa9005d8..dbc6aac6b59a329f0685b36880d268217d5a178a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt
@@ -43,15 +43,17 @@ import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory
 import org.matrix.olm.OlmManager
 import java.io.File
 
-@Component(modules = [
-    MatrixModule::class,
-    NetworkModule::class,
-    AuthModule::class,
-    RawModule::class,
-    SettingsModule::class,
-    SystemModule::class,
-    NoOpTestModule::class
-])
+@Component(
+        modules = [
+            MatrixModule::class,
+            NetworkModule::class,
+            AuthModule::class,
+            RawModule::class,
+            SettingsModule::class,
+            SystemModule::class,
+            NoOpTestModule::class
+        ]
+)
 @MatrixScope
 internal interface MatrixComponent {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt
index 9cab307c6153638cffcb76e84279b5346cc71a78..49713a1d7f3502f83782f3193e81c8b9c10c7f62 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt
@@ -36,7 +36,8 @@ internal object MatrixModule {
     @Provides
     @MatrixScope
     fun providesMatrixCoroutineDispatchers(): MatrixCoroutineDispatchers {
-        return MatrixCoroutineDispatchers(io = Dispatchers.IO,
+        return MatrixCoroutineDispatchers(
+                io = Dispatchers.IO,
                 computation = Dispatchers.Default,
                 main = Dispatchers.Main,
                 crypto = createBackgroundHandler("Crypto_Thread").asCoroutineDispatcher(),
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixScope.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixScope.kt
index b027d47144190c1c465b81f56348de422318bb6d..21e324c05f1909cc3eb636091587335a39f731e2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixScope.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixScope.kt
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.di
 import javax.inject.Scope
 
 /**
- * Use the annotation @MatrixScope to annotate classes we want the SDK to instantiate only once
+ * Use the annotation @MatrixScope to annotate classes we want the SDK to instantiate only once.
  */
 @Scope
 @MustBeDocumented
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MoshiProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MoshiProvider.kt
index 10b0d4fb13136029292bf774ce30f6789cdcaa07..8f007f227c27e6232b41e7c125811933a403216c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MoshiProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MoshiProvider.kt
@@ -46,17 +46,18 @@ internal object MoshiProvider {
             .add(TlsVersionMoshiAdapter())
             // Use addLast here so we can inject a SplitLazyRoomSyncJsonAdapter later to override the default parsing.
             .addLast(DefaultLazyRoomSyncEphemeralJsonAdapter())
-            .add(RuntimeJsonAdapterFactory.of(MessageContent::class.java, "msgtype", MessageDefaultContent::class.java)
-                    .registerSubtype(MessageTextContent::class.java, MessageType.MSGTYPE_TEXT)
-                    .registerSubtype(MessageNoticeContent::class.java, MessageType.MSGTYPE_NOTICE)
-                    .registerSubtype(MessageEmoteContent::class.java, MessageType.MSGTYPE_EMOTE)
-                    .registerSubtype(MessageAudioContent::class.java, MessageType.MSGTYPE_AUDIO)
-                    .registerSubtype(MessageImageContent::class.java, MessageType.MSGTYPE_IMAGE)
-                    .registerSubtype(MessageVideoContent::class.java, MessageType.MSGTYPE_VIDEO)
-                    .registerSubtype(MessageLocationContent::class.java, MessageType.MSGTYPE_LOCATION)
-                    .registerSubtype(MessageFileContent::class.java, MessageType.MSGTYPE_FILE)
-                    .registerSubtype(MessageVerificationRequestContent::class.java, MessageType.MSGTYPE_VERIFICATION_REQUEST)
-                    .registerSubtype(MessagePollResponseContent::class.java, MessageType.MSGTYPE_POLL_RESPONSE)
+            .add(
+                    RuntimeJsonAdapterFactory.of(MessageContent::class.java, "msgtype", MessageDefaultContent::class.java)
+                            .registerSubtype(MessageTextContent::class.java, MessageType.MSGTYPE_TEXT)
+                            .registerSubtype(MessageNoticeContent::class.java, MessageType.MSGTYPE_NOTICE)
+                            .registerSubtype(MessageEmoteContent::class.java, MessageType.MSGTYPE_EMOTE)
+                            .registerSubtype(MessageAudioContent::class.java, MessageType.MSGTYPE_AUDIO)
+                            .registerSubtype(MessageImageContent::class.java, MessageType.MSGTYPE_IMAGE)
+                            .registerSubtype(MessageVideoContent::class.java, MessageType.MSGTYPE_VIDEO)
+                            .registerSubtype(MessageLocationContent::class.java, MessageType.MSGTYPE_LOCATION)
+                            .registerSubtype(MessageFileContent::class.java, MessageType.MSGTYPE_FILE)
+                            .registerSubtype(MessageVerificationRequestContent::class.java, MessageType.MSGTYPE_VERIFICATION_REQUEST)
+                            .registerSubtype(MessagePollResponseContent::class.java, MessageType.MSGTYPE_POLL_RESPONSE)
             )
             .add(SerializeNulls.JSON_ADAPTER_FACTORY)
             .build()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/StringQualifiers.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/StringQualifiers.kt
index d74a8dce570ac5c522cdf682565fe6eb921dd10e..05ba6e408c58576ebbb3dbdf097dcda60d466908 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/StringQualifiers.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/StringQualifiers.kt
@@ -19,28 +19,28 @@ package org.matrix.android.sdk.internal.di
 import javax.inject.Qualifier
 
 /**
- * Used to inject the userId
+ * Used to inject the userId.
  */
 @Qualifier
 @Retention(AnnotationRetention.RUNTIME)
 internal annotation class UserId
 
 /**
- * Used to inject the deviceId
+ * Used to inject the deviceId.
  */
 @Qualifier
 @Retention(AnnotationRetention.RUNTIME)
 internal annotation class DeviceId
 
 /**
- * Used to inject the md5 of the userId
+ * Used to inject the md5 of the userId.
  */
 @Qualifier
 @Retention(AnnotationRetention.RUNTIME)
 internal annotation class UserMd5
 
 /**
- * Used to inject the sessionId, which is defined as md5(userId|deviceId)
+ * Used to inject the sessionId, which is defined as md5(userId|deviceId).
  */
 @Qualifier
 @Retention(AnnotationRetention.RUNTIME)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/WorkManagerProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/WorkManagerProvider.kt
index fedd7d05f90117a9a1176c6d9d7a3db7db8f8f9a..c59936af94d314a31dd11708731c0ed2b4038132 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/WorkManagerProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/WorkManagerProvider.kt
@@ -50,14 +50,14 @@ internal class WorkManagerProvider @Inject constructor(
     }
 
     /**
-     * Create a OneTimeWorkRequestBuilder, with the Matrix SDK tag
+     * Create a OneTimeWorkRequestBuilder, with the Matrix SDK tag.
      */
     inline fun <reified W : ListenableWorker> matrixOneTimeWorkRequestBuilder() =
             OneTimeWorkRequestBuilder<W>()
                     .addTag(tag)
 
     /**
-     * Create a PeriodicWorkRequestBuilder, with the Matrix SDK tag
+     * Create a PeriodicWorkRequestBuilder, with the Matrix SDK tag.
      */
     inline fun <reified W : ListenableWorker> matrixPeriodicWorkRequestBuilder(repeatInterval: Long,
                                                                                repeatIntervalTimeUnit: TimeUnit) =
@@ -65,7 +65,7 @@ internal class WorkManagerProvider @Inject constructor(
                     .addTag(tag)
 
     /**
-     * Cancel all works instantiated by the Matrix SDK for the current session, and not those from the SDK client, or for other sessions
+     * Cancel all works instantiated by the Matrix SDK for the current session, and not those from the SDK client, or for other sessions.
      */
     fun cancelAllWorks() {
         workManager.let {
@@ -84,9 +84,11 @@ internal class WorkManagerProvider @Inject constructor(
                     if (workInfo?.state?.isFinished == true) {
                         checkWorkerLiveState.removeObserver(this)
                         if (workInfo.state == WorkInfo.State.FAILED) {
-                            throw RuntimeException("MatrixWorkerFactory is not being set on your worker configuration.\n" +
-                                    "Makes sure to add it to a DelegatingWorkerFactory if you have your own factory or use it directly.\n" +
-                                    "You can grab the instance through the Matrix class.")
+                            throw RuntimeException(
+                                    "MatrixWorkerFactory is not being set on your worker configuration.\n" +
+                                            "Makes sure to add it to a DelegatingWorkerFactory if you have your own factory or use it directly.\n" +
+                                            "You can grab the instance through the Matrix class."
+                            )
                         }
                     }
                 }
@@ -99,7 +101,7 @@ internal class WorkManagerProvider @Inject constructor(
         private const val MATRIX_SDK_TAG_PREFIX = "MatrixSDK-"
 
         /**
-         * Default constraints: connected network
+         * Default constraints: connected network.
          */
         val workConstraints = Constraints.Builder()
                 .setRequiredNetworkType(NetworkType.CONNECTED)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/extensions/Primitives.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/extensions/Primitives.kt
index 290f06142c6e0f435070bcb8096cb825af900a8c..c08dfa02e8126a9c8a7414282415a30a9877e959 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/extensions/Primitives.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/extensions/Primitives.kt
@@ -17,6 +17,6 @@
 package org.matrix.android.sdk.internal.extensions
 
 /**
- * Convert a signed byte to a int value
+ * Convert a signed byte to a int value.
  */
 internal fun Byte.toUnsignedInt() = toInt() and 0xff
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/extensions/RealmExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/extensions/RealmExtensions.kt
index 28b9f6418826886193330fd5e14ef4f5a4c8df52..00cbe0aa85ebb394c02e205be79ad84583557721 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/extensions/RealmExtensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/extensions/RealmExtensions.kt
@@ -26,7 +26,7 @@ internal fun RealmObject.assertIsManaged() {
 }
 
 /**
- * Clear a RealmList by deleting all its items calling the provided lambda
+ * Clear a RealmList by deleting all its items calling the provided lambda.
  */
 internal fun <T> RealmList<T>.clearWith(delete: (T) -> Unit) {
     while (!isEmpty()) {
@@ -35,7 +35,7 @@ internal fun <T> RealmList<T>.clearWith(delete: (T) -> Unit) {
 }
 
 /**
- * Schedule a refresh of the HomeServers capabilities
+ * Schedule a refresh of the HomeServers capabilities.
  */
 internal fun RealmObjectSchema?.forceRefreshOfHomeServerCapabilities(): RealmObjectSchema? {
     return this?.transform { obj ->
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/WellKnown.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/WellKnown.kt
index 3b4bd1b1a3e87986588b9fea0fbfa0646c4184aa..a754a0da967c221111c64c4bbbd2641298a36f99 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/WellKnown.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/WellKnown.kt
@@ -63,7 +63,7 @@ class WellKnown {
     var integrations: Map<String, *>? = null
 
     /**
-     * Returns the list of integration managers proposed
+     * Returns the list of integration managers proposed.
      */
     fun getIntegrationManagers(): List<WellKnownManagerConfig> {
         val managers = ArrayList<WellKnownManagerConfig>()
@@ -76,10 +76,12 @@ class WellKnown {
                         if (apiUrl != null &&
                                 apiUrl.startsWith("https://") &&
                                 uiUrl!!.startsWith("https://")) {
-                            managers.add(WellKnownManagerConfig(
-                                    apiUrl = apiUrl,
-                                    uiUrl = uiUrl
-                            ))
+                            managers.add(
+                                    WellKnownManagerConfig(
+                                            apiUrl = apiUrl,
+                                            uiUrl = uiUrl
+                                    )
+                            )
                         }
                     }
                 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConnectivityChecker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConnectivityChecker.kt
index 3d2b2bfbfb8c19f7e4cad09f8b2949c2eaaad3af..65bf3fcadf926303670501e01b92b54f07fef1e2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConnectivityChecker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConnectivityChecker.kt
@@ -27,7 +27,7 @@ import javax.inject.Inject
 
 internal interface NetworkConnectivityChecker {
     /**
-     * Returns true when internet is available
+     * Returns true when internet is available.
      */
     @WorkerThread
     fun hasInternetAccess(forcePing: Boolean): Boolean
@@ -59,7 +59,7 @@ internal class DefaultNetworkConnectivityChecker @Inject constructor(private val
     }
 
     /**
-     * Returns true when internet is available
+     * Returns true when internet is available.
      */
     @WorkerThread
     override fun hasInternetAccess(forcePing: Boolean): Boolean {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt
index 60055be9ec14de6f0b5ed9cb5b0d4c55fe2502f1..5268ea851d5f54d6e67562b4fa52ae4ab5fb045e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt
@@ -53,21 +53,21 @@ internal suspend fun okhttp3.Call.awaitResponse(): okhttp3.Response {
 }
 
 /**
- * Convert a retrofit Response to a Failure, and eventually parse errorBody to convert it to a MatrixError
+ * Convert a retrofit Response to a Failure, and eventually parse errorBody to convert it to a [MatrixError].
  */
 internal fun <T> Response<T>.toFailure(globalErrorReceiver: GlobalErrorReceiver?): Failure {
     return toFailure(errorBody(), code(), globalErrorReceiver)
 }
 
 /**
- * Convert a HttpException to a Failure, and eventually parse errorBody to convert it to a MatrixError
+ * Convert a HttpException to a Failure, and eventually parse errorBody to convert it to a [MatrixError].
  */
 internal fun HttpException.toFailure(globalErrorReceiver: GlobalErrorReceiver?): Failure {
     return toFailure(response()?.errorBody(), code(), globalErrorReceiver)
 }
 
 /**
- * Convert a okhttp3 Response to a Failure, and eventually parse errorBody to convert it to a MatrixError
+ * Convert a okhttp3 Response to a Failure, and eventually parse errorBody to convert it to a [MatrixError].
  */
 internal fun okhttp3.Response.toFailure(globalErrorReceiver: GlobalErrorReceiver?): Failure {
     return toFailure(body, code, globalErrorReceiver)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitFactory.kt
index 0a797c8bc00909f9c88b9c5f1caed260c26ebb3a..b2eea84b07e630820b630c0aa806d9726a5b3ba7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitFactory.kt
@@ -29,7 +29,7 @@ import javax.inject.Inject
 internal class RetrofitFactory @Inject constructor(private val moshi: Moshi) {
 
     /**
-     * Use only for authentication service
+     * Use only for authentication service.
      */
     fun create(okHttpClient: OkHttpClient, baseUrl: String): Retrofit {
         return Retrofit.Builder()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/CheckNumberType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/CheckNumberType.kt
index 6efa347d3ac374075f0eaddbc95996a0a8f26330..8b549782795866699e2c023766f24d5b5c605272 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/CheckNumberType.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/CheckNumberType.kt
@@ -33,7 +33,7 @@ internal interface CheckNumberType {
     companion object {
         val JSON_ADAPTER_FACTORY = object : JsonAdapter.Factory {
             @Nullable
-            override fun create(type: Type, annotations: Set<Annotation?>?, moshi: Moshi): JsonAdapter<*>? {
+            override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
                 if (type !== Any::class.java) {
                     return null
                 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/RuntimeJsonAdapterFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/RuntimeJsonAdapterFactory.kt
index 0aaa4991cde768ef84d047f25fffe6ac739ee1f2..40d174ee2d5df87d09b22aa8bf6847467ed601f8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/RuntimeJsonAdapterFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/RuntimeJsonAdapterFactory.kt
@@ -63,8 +63,10 @@ internal class RuntimeJsonAdapterFactory<T>(
         }
         val fallbackAdapter = moshi.adapter<Any>(fallbackType)
         val objectJsonAdapter = moshi.adapter(Any::class.java)
-        return RuntimeJsonAdapter(labelKey, labelToAdapter, typeToLabel,
-                objectJsonAdapter, fallbackAdapter).nullSafe()
+        return RuntimeJsonAdapter(
+                labelKey, labelToAdapter, typeToLabel,
+                objectJsonAdapter, fallbackAdapter
+        ).nullSafe()
     }
 
     @Suppress("UNCHECKED_CAST")
@@ -77,8 +79,10 @@ internal class RuntimeJsonAdapterFactory<T>(
         override fun fromJson(reader: JsonReader): Any? {
             val peekedToken = reader.peek()
             if (peekedToken != JsonReader.Token.BEGIN_OBJECT) {
-                throw JsonDataException("Expected BEGIN_OBJECT but was " + peekedToken +
-                        " at path " + reader.path)
+                throw JsonDataException(
+                        "Expected BEGIN_OBJECT but was " + peekedToken +
+                                " at path " + reader.path
+                )
             }
             val jsonValue = reader.readJsonValue()
             val jsonObject = jsonValue as Map<String, Any>?
@@ -91,13 +95,15 @@ internal class RuntimeJsonAdapterFactory<T>(
         override fun toJson(writer: JsonWriter, value: Any?) {
             val type: Class<*> = value!!.javaClass
             val label = typeToLabel[type]
-                    ?: throw IllegalArgumentException("Expected one of " +
-                            typeToLabel.keys +
-                            " but found " +
-                            value +
-                            ", a " +
-                            value.javaClass +
-                            ". Register this subtype.")
+                    ?: throw IllegalArgumentException(
+                            "Expected one of " +
+                                    typeToLabel.keys +
+                                    " but found " +
+                                    value +
+                                    ", a " +
+                                    value.javaClass +
+                                    ". Register this subtype."
+                    )
             val adapter = labelToAdapter[label]!!
             val jsonValue = adapter.toJsonValue(value) as Map<String, Any>?
             val valueWithLabel: MutableMap<String, Any> = LinkedHashMap(1 + jsonValue!!.size)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt
index d8bdc5fc2b2b29fa01a707d845af712997d42c1b..2ef40fe2a3fbb162b8ce3ef1800081cdffd18124 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt
@@ -33,7 +33,7 @@ import javax.net.ssl.TrustManagerFactory
 import javax.net.ssl.X509TrustManager
 
 /**
- * Various utility classes for dealing with X509Certificates
+ * Various utility classes for dealing with X509Certificates.
  */
 internal object CertUtil {
 
@@ -43,7 +43,7 @@ internal object CertUtil {
     private val hexArray = "0123456789ABCDEF".toCharArray()
 
     /**
-     * Generates the SHA-256 fingerprint of the given certificate
+     * Generates the SHA-256 fingerprint of the given certificate.
      *
      * @param cert the certificate.
      * @return the finger print
@@ -55,7 +55,7 @@ internal object CertUtil {
     }
 
     /**
-     * Generates the SHA-1 fingerprint of the given certificate
+     * Generates the SHA-1 fingerprint of the given certificate.
      *
      * @param cert the certificated
      * @return the SHA1 fingerprint
@@ -109,7 +109,7 @@ internal object CertUtil {
 
     /**
      * Recursively checks the exception to see if it was caused by an
-     * UnrecognizedCertificateException
+     * UnrecognizedCertificateException.
      *
      * @param root the throwable.
      * @return The UnrecognizedCertificateException if exists, else null.
@@ -250,7 +250,7 @@ internal object CertUtil {
         builder.supportsTlsExtensions(hsConfig.shouldAcceptTlsExtensions)
         val list = ArrayList<ConnectionSpec>()
         list.add(builder.build())
-        // TODO: we should display a warning if user enter an http url
+        // TODO we should display a warning if user enter an http url
         if (hsConfig.allowHttpExtension || hsConfig.homeServerUriBase.toString().startsWith("http://")) {
             list.add(ConnectionSpec.CLEARTEXT)
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt
index 7294ce4abf0fbc80edf572cac5e4cfac634ac2f8..c5ea2d48ad4e517cd8d75cacd2598b46140f6e80 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt
@@ -35,8 +35,10 @@ internal fun RealmQuery<RoomSummaryEntity>.process(sortOrder: RoomSortOrder): Re
                     arrayOf(
                             RoomSummaryEntityFields.IS_FAVOURITE,
                             RoomSummaryEntityFields.IS_LOW_PRIORITY,
-                            RoomSummaryEntityFields.LAST_ACTIVITY_TIME),
-                    arrayOf(Sort.DESCENDING, Sort.ASCENDING, Sort.DESCENDING))
+                            RoomSummaryEntityFields.LAST_ACTIVITY_TIME
+                    ),
+                    arrayOf(Sort.DESCENDING, Sort.ASCENDING, Sort.DESCENDING)
+            )
         }
         RoomSortOrder.NONE                  -> {
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GlobalRealmMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GlobalRealmMigration.kt
index 8dffac5fa074f1705a8c2ef62091af72bcc65641..a9dfd47b5a46a42ff94443d3d6aa00b51904956b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GlobalRealmMigration.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GlobalRealmMigration.kt
@@ -24,8 +24,8 @@ import javax.inject.Inject
 
 internal class GlobalRealmMigration @Inject constructor() : RealmMigration {
     /**
-     * Forces all GlobalRealmMigration instances to be equal
-     * Avoids Realm throwing when multiple instances of the migration are set
+     * Forces all GlobalRealmMigration instances to be equal.
+     * Avoids Realm throwing when multiple instances of the migration are set.
      */
     override fun equals(other: Any?) = other is GlobalRealmMigration
     override fun hashCode() = 2000
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GlobalRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GlobalRealmModule.kt
index 770a49c90411574ebc70c800c1b308a90682145a..2d9ec8e820e9f0e1c194c3da1b1245a83d7dc1c5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GlobalRealmModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GlobalRealmModule.kt
@@ -21,11 +21,13 @@ import org.matrix.android.sdk.internal.database.model.KnownServerUrlEntity
 import org.matrix.android.sdk.internal.database.model.RawCacheEntity
 
 /**
- * Realm module for global classes
+ * Realm module for global classes.
  */
-@RealmModule(library = true,
+@RealmModule(
+        library = true,
         classes = [
             RawCacheEntity::class,
             KnownServerUrlEntity::class
-        ])
+        ]
+)
 internal class GlobalRealmModule
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt
index 78f1c84f3dd417d99cc4c5620581fda8bc46476b..760aa410817389bce1a762c2917669ebbccc3026 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt
@@ -72,12 +72,12 @@ internal class DefaultFileService @Inject constructor(
 
     /**
      * Retain ongoing downloads to avoid re-downloading and already downloading file
-     * map of mxCurl to callbacks
+     * map of mxCurl to callbacks.
      */
     private val ongoing = mutableMapOf<String, CompletableDeferred<File>>()
 
     /**
-     * Download file in the cache folder, and eventually decrypt it
+     * Download file in the cache folder, and eventually decrypt it.
      * TODO looks like files are copied 3 times
      */
     override suspend fun downloadFile(fileName: String,
@@ -88,7 +88,7 @@ internal class DefaultFileService @Inject constructor(
 
         Timber.v("## FileService downloadFile $url")
 
-        // TODO: Remove use of `synchronized` in suspend function.
+        // TODO Remove use of `synchronized` in suspend function.
         val existingDownload = synchronized(ongoing) {
             val existing = ongoing[url]
             if (existing != null) {
@@ -312,7 +312,7 @@ 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)
+     * (if not other app won't be able to access it).
      */
     override fun getTemporarySharableURI(mxcUrl: String?,
                                          fileName: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
index 76e5d84e56622b1753098998f103e7e744699be1..050480e6c955d58a4d4e01ed749c82cd1ba30ed8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
@@ -21,12 +21,8 @@ import dagger.Component
 import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
 import org.matrix.android.sdk.api.auth.data.SessionParams
 import org.matrix.android.sdk.api.session.Session
-import org.matrix.android.sdk.internal.crypto.CancelGossipRequestWorker
 import org.matrix.android.sdk.internal.crypto.CryptoModule
-import org.matrix.android.sdk.internal.crypto.SendGossipRequestWorker
-import org.matrix.android.sdk.internal.crypto.SendGossipWorker
 import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
-import org.matrix.android.sdk.internal.crypto.verification.SendVerificationMessageWorker
 import org.matrix.android.sdk.internal.di.MatrixComponent
 import org.matrix.android.sdk.internal.federation.FederationModule
 import org.matrix.android.sdk.internal.network.NetworkConnectivityChecker
@@ -68,7 +64,8 @@ import org.matrix.android.sdk.internal.session.widgets.WidgetModule
 import org.matrix.android.sdk.internal.task.TaskExecutor
 import org.matrix.android.sdk.internal.util.system.SystemModule
 
-@Component(dependencies = [MatrixComponent::class],
+@Component(
+        dependencies = [MatrixComponent::class],
         modules = [
             SessionModule::class,
             RoomModule::class,
@@ -132,14 +129,6 @@ internal interface SessionComponent {
 
     fun inject(worker: AddPusherWorker)
 
-    fun inject(worker: SendVerificationMessageWorker)
-
-    fun inject(worker: SendGossipRequestWorker)
-
-    fun inject(worker: CancelGossipRequestWorker)
-
-    fun inject(worker: SendGossipWorker)
-
     fun inject(worker: UpdateTrustWorker)
 
     @Component.Factory
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt
index 0aae9f31058a253b92d65c3e40e50e42f7c5c7d1..7ceb89e892c24c8a27649b9985746f59633c0fba 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt
@@ -49,7 +49,6 @@ import org.matrix.android.sdk.api.util.md5
 import org.matrix.android.sdk.internal.crypto.secrets.DefaultSharedSecretStorageService
 import org.matrix.android.sdk.internal.crypto.tasks.DefaultRedactEventTask
 import org.matrix.android.sdk.internal.crypto.tasks.RedactEventTask
-import org.matrix.android.sdk.internal.crypto.verification.VerificationMessageProcessor
 import org.matrix.android.sdk.internal.database.EventInsertLiveObserver
 import org.matrix.android.sdk.internal.database.RealmSessionProvider
 import org.matrix.android.sdk.internal.database.SessionRealmConfigurationFactory
@@ -318,10 +317,6 @@ internal abstract class SessionModule {
     @IntoSet
     abstract fun bindRoomCreateEventProcessor(processor: RoomCreateEventProcessor): EventInsertLiveProcessor
 
-    @Binds
-    @IntoSet
-    abstract fun bindVerificationMessageProcessor(processor: VerificationMessageProcessor): EventInsertLiveProcessor
-
     @Binds
     @IntoSet
     abstract fun bindCallEventProcessor(processor: CallEventProcessor): EventInsertLiveProcessor
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/AccountAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/AccountAPI.kt
index a04d0f2686f935de33c0f4f95ded495bbecc98e3..4bd3b6360d91f7e9f54a1e68014309f96f16248b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/AccountAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/AccountAPI.kt
@@ -30,7 +30,7 @@ internal interface AccountAPI {
     suspend fun changePassword(@Body params: ChangePasswordParams)
 
     /**
-     * Deactivate the user account
+     * Deactivate the user account.
      *
      * @param params the deactivate account params
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/GetTurnServerTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/GetTurnServerTask.kt
index d53ddb737116385dde615ad9a342bfc5345ad8a0..1313fcaa62484b3d03d5c699c79a06bd53575d19 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/GetTurnServerTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/GetTurnServerTask.kt
@@ -22,16 +22,16 @@ import org.matrix.android.sdk.internal.network.executeRequest
 import org.matrix.android.sdk.internal.task.Task
 import javax.inject.Inject
 
-internal abstract class GetTurnServerTask : Task<GetTurnServerTask.Params, TurnServerResponse> {
-    object Params
-}
+internal abstract class GetTurnServerTask : Task<Unit, TurnServerResponse>
 
-internal class DefaultGetTurnServerTask @Inject constructor(private val voipAPI: VoipApi,
-                                                            private val globalErrorReceiver: GlobalErrorReceiver) : GetTurnServerTask() {
+internal class DefaultGetTurnServerTask @Inject constructor(
+        private val voipApi: VoipApi,
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : GetTurnServerTask() {
 
-    override suspend fun execute(params: Params): TurnServerResponse {
+    override suspend fun execute(params: Unit): TurnServerResponse {
         return executeRequest(globalErrorReceiver) {
-            voipAPI.getTurnServer()
+            voipApi.getTurnServer()
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/TurnServerDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/TurnServerDataSource.kt
index 8e2ac5e17e7626dc04ef64d1285d08d1d8cbc24c..126a581fa4729e36ac5f65bd6f35bc2b78909646 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/TurnServerDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/TurnServerDataSource.kt
@@ -39,7 +39,7 @@ internal class TurnServerDataSource @Inject constructor(private val turnServerTa
     }
 
     suspend fun getTurnServer(): TurnServerResponse {
-        return cachedTurnServerResponse.data ?: turnServerTask.execute(GetTurnServerTask.Params).also {
+        return cachedTurnServerResponse.data ?: turnServerTask.execute(Unit).also {
             cachedTurnServerResponse.data = it
         }
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageExifTagRemover.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageExifTagRemover.kt
index 239a768498500f298815e7d1e602163f58d3f919..3fa9ffb0e118371a050196e6158c6ea3527579d6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageExifTagRemover.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageExifTagRemover.kt
@@ -31,9 +31,8 @@ import java.io.FileOutputStream
 import javax.inject.Inject
 
 /**
- * This class is responsible for removing Exif tags from image files
+ * This class is responsible for removing Exif tags from image files.
  */
-
 internal class ImageExifTagRemover @Inject constructor(
         private val temporaryFileCreator: TemporaryFileCreator,
         private val coroutineDispatchers: MatrixCoroutineDispatchers
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
index 75a79abcdbcd2aad7e828ebfe9b0ceb8de796da1..5a00c4b5b477f53bbeffef003063145bc8ca455b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
@@ -62,8 +62,8 @@ private data class NewAttachmentAttributes(
 )
 
 /**
- * Possible previous worker: None
- * Possible next worker    : Always [MultipleEventSendingDispatcherWorker]
+ * Possible previous worker: None.
+ * Possible next worker    : Always [MultipleEventSendingDispatcherWorker].
  */
 internal class UploadContentWorker(val context: Context, params: WorkerParameters, sessionManager: SessionManager) :
         SessionSafeCoroutineWorker<UploadContentWorker.Params>(context, params, sessionManager, Params::class.java) {
@@ -289,12 +289,14 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
 
                 val uploadThumbnailResult = dealWithThumbnail(params)
 
-                handleSuccess(params,
+                handleSuccess(
+                        params,
                         contentUploadResponse.contentUri,
                         uploadedFileEncryptedFileInfo,
                         uploadThumbnailResult?.uploadedThumbnailUrl,
                         uploadThumbnailResult?.uploadedThumbnailEncryptedFileInfo,
-                        newAttachmentAttributes)
+                        newAttachmentAttributes
+                )
             } catch (t: Throwable) {
                 Timber.e(t, "## ERROR ${t.localizedMessage}")
                 handleFailure(params, t)
@@ -316,7 +318,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
     )
 
     /**
-     * If appropriate, it will create and upload a thumbnail
+     * If appropriate, it will create and upload a thumbnail.
      */
     private suspend fun dealWithThumbnail(params: Params): UploadThumbnailResult? {
         return thumbnailExtractor.extractThumbnail(params.attachment)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerRealmModule.kt
index bb53140ad989bfd2dec97b0f3ddaedd89455277c..1872bb72a9f7173f634487deddd812cb56db5416 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerRealmModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerRealmModule.kt
@@ -19,11 +19,13 @@ package org.matrix.android.sdk.internal.session.contentscanner.db
 import io.realm.annotations.RealmModule
 
 /**
- * Realm module for content scanner classes
+ * Realm module for content scanner classes.
  */
-@RealmModule(library = true,
+@RealmModule(
+        library = true,
         classes = [
             ContentScannerInfoEntity::class,
             ContentScanResultEntity::class
-        ])
+        ]
+)
 internal class ContentScannerRealmModule
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/ScanResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/ScanResponse.kt
index f783fe0a6c2c384a551af47803c3cfdbc141d2b2..85d7f2e09420da44cdf528de9ca3d6f32102f384 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/ScanResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/model/ScanResponse.kt
@@ -20,10 +20,14 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
+ * Example:
+ * <pre>
  * {
  *      "clean": true,
  *      "info": "File clean at 6/7/2018, 6:02:40 PM"
  *  }
+ * </pre>
+ * .
  */
 @JsonClass(generateAdapter = true)
 internal data class ScanResponse(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/directory/DirectoryAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/directory/DirectoryAPI.kt
index 16c57baafc59ddd5f76c75889fea5bfe35e5240f..19b9130fc4b6e7f63954c518fcb8d81a3f61d74f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/directory/DirectoryAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/directory/DirectoryAPI.kt
@@ -61,7 +61,7 @@ internal interface DirectoryAPI {
                              @Body body: AddRoomAliasBody)
 
     /**
-     * Delete a room alias
+     * Delete a room alias.
      * @param roomAlias the room alias.
      */
     @DELETE(NetworkConstants.URI_API_PREFIX_PATH_R0 + "directory/room/{roomAlias}")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterApi.kt
index 2809dea23b71b83dd2b584c9359cdc636450b068..dab801360fd99e98aec6095020c76ba6b7437e6f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterApi.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterApi.kt
@@ -25,7 +25,7 @@ import retrofit2.http.Path
 internal interface FilterApi {
 
     /**
-     * Upload FilterBody to get a filter_id which can be used for /sync requests
+     * Upload FilterBody to get a filter_id which can be used for /sync requests.
      *
      * @param userId the user id
      * @param body   the Json representation of a FilterBody object
@@ -35,7 +35,7 @@ internal interface FilterApi {
                              @Body body: Filter): FilterResponse
 
     /**
-     * Gets a filter with a given filterId from the homeserver
+     * Gets a filter with a given filterId from the homeserver.
      *
      * @param userId   the user id
      * @param filterId the filterID
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterRepository.kt
index df615395478fcaeac1b5feae4af9d0587878bf99..f40231c8cffa93d7f1bf44828143867685b640bf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterRepository.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterRepository.kt
@@ -19,22 +19,22 @@ package org.matrix.android.sdk.internal.session.filter
 internal interface FilterRepository {
 
     /**
-     * Return true if the filterBody has changed, or need to be sent to the server
+     * Return true if the filterBody has changed, or need to be sent to the server.
      */
     suspend fun storeFilter(filter: Filter, roomEventFilter: RoomEventFilter): Boolean
 
     /**
-     * Set the filterId of this filter
+     * Set the filterId of this filter.
      */
     suspend fun storeFilterId(filter: Filter, filterId: String)
 
     /**
-     * Return filter json or filter id
+     * Return filter json or filter id.
      */
     suspend fun getFilter(): String
 
     /**
-     * Return the room filter
+     * Return the room filter.
      */
     suspend fun getRoomFilter(): String
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterUtil.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterUtil.kt
index bd7f0ad402fc9feff402255400e67d51dca5c418..562fea88b66c0b7fc015f98f2fe75b26618900b6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterUtil.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterUtil.kt
@@ -81,8 +81,7 @@ internal object FilterUtil {
     } */
 
     /**
-     * Compute a new filter to enable or disable the lazy loading
-     *
+     * Compute a new filter to enable or disable the lazy loading.
      *
      * If lazy loading is on, the filter will looks like
      * {"room":{"state":{"lazy_load_members":true})}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/RoomFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/RoomFilter.kt
index 585d013eaef4e3105acb29292948b890dbff0cbc..72b1af52b82a3bd9bc8268007d84697d77ccae19 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/RoomFilter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/RoomFilter.kt
@@ -40,7 +40,7 @@ internal data class RoomFilter(
          */
         @Json(name = "ephemeral") val ephemeral: RoomEventFilter? = null,
         /**
-         * Include rooms that the user has left in the sync, default false
+         * Include rooms that the user has left in the sync, default false.
          */
         @Json(name = "include_leave") val includeLeave: Boolean? = null,
         /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/SaveFilterTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/SaveFilterTask.kt
index 3cac89ce285551228e8d7d8998a2e08449f8814b..e9d5b876a8d14512ec122aa72bdc9ab65589aea9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/SaveFilterTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/SaveFilterTask.kt
@@ -24,7 +24,7 @@ import org.matrix.android.sdk.internal.task.Task
 import javax.inject.Inject
 
 /**
- * Save a filter, in db and if any changes, upload to the server
+ * Save a filter, in db and if any changes, upload to the server.
  */
 internal interface SaveFilterTask : Task<SaveFilterTask.Params, Unit> {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataWorker.kt
index 716859f195f75736591bdc8f9192eb7996cbd6ea..21582cb4bed7b2867768c73e768b44b469d08f96 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataWorker.kt
@@ -26,8 +26,8 @@ import org.matrix.android.sdk.internal.worker.SessionWorkerParams
 import javax.inject.Inject
 
 /**
- * Possible previous worker: None
- * Possible next worker    : None
+ * Possible previous worker: None.
+ * Possible next worker    : None.
  */
 internal class GetGroupDataWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
         SessionSafeCoroutineWorker<GetGroupDataWorker.Params>(context, params, sessionManager, Params::class.java) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GroupAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GroupAPI.kt
index 58dcc57dd6ab24e901e58097773890d56ff52467..c9d25b910441388d331af54a81c1da767d16a5b6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GroupAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GroupAPI.kt
@@ -26,7 +26,7 @@ import retrofit2.http.Path
 internal interface GroupAPI {
 
     /**
-     * Request a group summary
+     * Request a group summary.
      *
      * @param groupId the group id
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/model/GroupSummaryRoomsSection.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/model/GroupSummaryRoomsSection.kt
index 8f9b29ed0a02f5344676181e6ec8365ab16ba971..87d07167ce2aad46469c1cc8bb95a54b1346b182 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/model/GroupSummaryRoomsSection.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/model/GroupSummaryRoomsSection.kt
@@ -29,6 +29,6 @@ internal data class GroupSummaryRoomsSection(
 
         @Json(name = "rooms") val rooms: List<String> = emptyList()
 
-        // @TODO: Check the meaning and the usage of these categories. This dictionary is empty FTM.
+        // TODO Check the meaning and the usage of these categories. This dictionary is empty FTM.
         // public Map<Object, Object> categories;
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/model/GroupSummaryUsersSection.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/model/GroupSummaryUsersSection.kt
index 799aa8a5b1010eb4ad6c1c1dbdbf608798682465..63608c582a66db0d2f7a96899999235583e747e3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/model/GroupSummaryUsersSection.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/model/GroupSummaryUsersSection.kt
@@ -30,6 +30,6 @@ internal data class GroupSummaryUsersSection(
 
         @Json(name = "users") val users: List<String> = emptyList()
 
-        // @TODO: Check the meaning and the usage of these roles. This dictionary is empty FTM.
+        // TODO Check the meaning and the usage of these roles. This dictionary is empty FTM.
         // public Map<Object, Object> roles;
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/CapabilitiesAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/CapabilitiesAPI.kt
index 7de0cc95928c784b4466b7a0fc371b425486b569..f658cda9739fb42dcd5b57b9bebe4dce11077250 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/CapabilitiesAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/CapabilitiesAPI.kt
@@ -22,19 +22,19 @@ import retrofit2.http.GET
 
 internal interface CapabilitiesAPI {
     /**
-     * Request the homeserver capabilities
+     * Request the homeserver capabilities.
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "capabilities")
     suspend fun getCapabilities(): GetCapabilitiesResult
 
     /**
-     * Request the versions
+     * Request the versions.
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_ + "versions")
     suspend fun getVersions(): Versions
 
     /**
-     * Ping the homeserver. We do not care about the returned data, so there is no use to parse them
+     * Ping the homeserver. We do not care about the returned data, so there is no use to parse them.
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_ + "versions")
     suspend fun ping()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt
index 55526b41db604d0126d0fe69e604bbcccfe3f5f0..95ff44807c85c7c7cf46f35458faf98686593282 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetCapabilitiesResult.kt
@@ -67,8 +67,8 @@ internal data class Capabilities(
         @Json(name = "m.room_versions")
         val roomVersions: RoomVersions? = null,
         /**
-         * Capability to indicate if the server supports MSC3440 Threading
-         * True if the user can use m.thread relation, false otherwise
+         * Capability to indicate if the server supports MSC3440 Threading.
+         * True if the user can use m.thread relation, false otherwise.
          */
         @Json(name = "m.thread")
         val threads: BooleanCapability? = null
@@ -98,6 +98,8 @@ internal data class RoomVersions(
         val available: JsonDict? = null,
 
         /**
+         * Example:
+         * <pre>
          *  "room_capabilities": {
          *      "knock" : {
          *              "preferred": "7",
@@ -108,6 +110,7 @@ internal data class RoomVersions(
          *              "support" : ["8", "9"]
          *      }
          * }
+         * </pre>.
          */
         @Json(name = "org.matrix.msc3244.room_capabilities")
         val roomCapabilities: JsonDict? = null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt
index 44e13d971a84b3d52a278a1b78783c73e907e75b..e9097e4d033f0721bc0f49d967413e7838be0f7f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt
@@ -94,10 +94,12 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
         }.getOrNull()
 
         val wellknownResult = runCatching {
-            getWellknownTask.execute(GetWellknownTask.Params(
-                    domain = userId.getDomain(),
-                    homeServerConnectionConfig = homeServerConnectionConfig
-            ))
+            getWellknownTask.execute(
+                    GetWellknownTask.Params(
+                            domain = userId.getDomain(),
+                            homeServerConnectionConfig = homeServerConnectionConfig
+                    )
+            )
         }.getOrNull()
 
         insertInDb(capabilities, mediaConfig, versions, wellknownResult)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt
index 4285f38893cdde2da859a85465d1c65aff6c8bbf..74838afc6587b6eacfd4b58a2550f3c0a9db8dcf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt
@@ -218,9 +218,11 @@ internal class DefaultIdentityService @Inject constructor(
             listeners.toList().forEach { tryOrNull { it.onIdentityServerChange() } }
         }
 
-        updateUserAccountDataTask.execute(UpdateUserAccountDataTask.IdentityParams(
-                identityContent = IdentityServerContent(baseUrl = url)
-        ))
+        updateUserAccountDataTask.execute(
+                UpdateUserAccountDataTask.IdentityParams(
+                        identityContent = IdentityServerContent(baseUrl = url)
+                )
+        )
     }
 
     override fun getUserConsent(): Boolean {
@@ -297,11 +299,13 @@ internal class DefaultIdentityService @Inject constructor(
     }
 
     override suspend fun sign3pidInvitation(identiyServer: String, token: String, secret: String): SignInvitationResult {
-        return sign3pidInvitationTask.execute(Sign3pidInvitationTask.Params(
-                url = identiyServer,
-                token = token,
-                privateKey = secret
-        ))
+        return sign3pidInvitationTask.execute(
+                Sign3pidInvitationTask.Params(
+                        url = identiyServer,
+                        token = token,
+                        privateKey = secret
+                )
+        )
     }
 
     override fun addListener(listener: IdentityServiceListener) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAPI.kt
index 7ca875867706eab5030c38d2b5464b595fb75fa8..aef86ed08efaed4a3fe1feee081a4c304ff2e056 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAPI.kt
@@ -34,8 +34,8 @@ import retrofit2.http.Path
 import retrofit2.http.Query
 
 /**
- * Ref: https://matrix.org/docs/spec/identity_service/latest
- * This contain the requests which need an identity server token
+ * Ref: https://matrix.org/docs/spec/identity_service/latest.
+ * This contain the requests which need an identity server token.
  */
 internal interface IdentityAPI {
     /**
@@ -69,8 +69,8 @@ internal interface IdentityAPI {
     suspend fun lookup(@Body body: IdentityLookUpParams): IdentityLookUpResponse
 
     /**
-     * Create a session to change the bind status of an email to an identity server
-     * The identity server will also send an email
+     * Create a session to change the bind status of an email to an identity server.
+     * The identity server will also send an email.
      *
      * @param body
      * @return the sid
@@ -79,8 +79,8 @@ internal interface IdentityAPI {
     suspend fun requestTokenToBindEmail(@Body body: IdentityRequestTokenForEmailBody): IdentityRequestTokenResponse
 
     /**
-     * Create a session to change the bind status of an phone number to an identity server
-     * The identity server will also send an SMS on the ThreePid provided
+     * Create a session to change the bind status of an phone number to an identity server.
+     * The identity server will also send an SMS on the ThreePid provided.
      *
      * @param body
      * @return the sid
@@ -99,9 +99,9 @@ internal interface IdentityAPI {
                             @Body body: IdentityRequestOwnershipParams): SuccessResult
 
     /**
-     * https://matrix.org/docs/spec/identity_service/r0.3.0#post-matrix-identity-v2-sign-ed25519
+     * https://matrix.org/docs/spec/identity_service/r0.3.0#post-matrix-identity-v2-sign-ed25519.
      *
-     * Have to rely on V1 for now
+     * Have to rely on V1 for now.
      */
     @POST(NetworkConstants.URI_IDENTITY_PATH_V1 + "sign-ed25519")
     suspend fun signInvitationDetails(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAuthAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAuthAPI.kt
index f77eb296aa9e48438206662fe1dee09d85718e77..85791f59a3755a9d664f8cc8b5e682d237a84c6f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAuthAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAuthAPI.kt
@@ -24,14 +24,14 @@ import retrofit2.http.GET
 import retrofit2.http.POST
 
 /**
- * Ref: https://matrix.org/docs/spec/identity_service/latest
- * This contain the requests which do not need an identity server token
+ * Ref: https://matrix.org/docs/spec/identity_service/latest.
+ * This contain the requests which do not need an identity server token.
  */
 internal interface IdentityAuthAPI {
 
     /**
-     * https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery
-     * Simple ping call to check if server exists and is alive
+     * https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery.
+     * Simple ping call to check if server exists and is alive.
      *
      * Ref: https://matrix.org/docs/spec/identity_service/unstable#status-check
      * https://matrix.org/docs/spec/identity_service/latest#get-matrix-identity-v2
@@ -42,7 +42,7 @@ internal interface IdentityAuthAPI {
     suspend fun ping()
 
     /**
-     * Ping v1 will be used to check outdated identity server
+     * Ping v1 will be used to check outdated identity server.
      */
     @GET("_matrix/identity/api/v1")
     suspend fun pingV1()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt
index f6ef370f8d3064a7c4561405311b522715ee30bb..f642ed4cf2f936574cf2de6366eac908f2b20396 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt
@@ -83,11 +83,13 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor(
         return try {
             LookUpData(hashedAddresses,
                     executeRequest(null) {
-                        identityAPI.lookup(IdentityLookUpParams(
-                                hashedAddresses,
-                                IdentityHashDetailResponse.ALGORITHM_SHA256,
-                                hashDetailResponse.pepper
-                        ))
+                        identityAPI.lookup(
+                                IdentityLookUpParams(
+                                        hashedAddresses,
+                                        IdentityHashDetailResponse.ALGORITHM_SHA256,
+                                        hashDetailResponse.pepper
+                                )
+                        )
                     })
         } catch (failure: Throwable) {
             // Catch invalid hash pepper and retry
@@ -117,8 +119,10 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor(
         return withOlmUtility { olmUtility ->
             threePids.map { threePid ->
                 base64ToBase64Url(
-                        olmUtility.sha256(threePid.value.lowercase(Locale.ROOT) +
-                                " " + threePid.toMedium() + " " + pepper)
+                        olmUtility.sha256(
+                                threePid.value.lowercase(Locale.ROOT) +
+                                        " " + threePid.toMedium() + " " + pepper
+                        )
                 )
             }
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityRequestTokenForBindingTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityRequestTokenForBindingTask.kt
index 9c89048176f6d8d918f324e6bf34845d882524dc..fe123096509fc4246693ec91a5cc3006ac0acbee 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityRequestTokenForBindingTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityRequestTokenForBindingTask.kt
@@ -57,18 +57,22 @@ internal class DefaultIdentityRequestTokenForBindingTask @Inject constructor(
 
         val tokenResponse = executeRequest(null) {
             when (params.threePid) {
-                is ThreePid.Email  -> identityAPI.requestTokenToBindEmail(IdentityRequestTokenForEmailBody(
-                        clientSecret = clientSecret,
-                        sendAttempt = sendAttempt,
-                        email = params.threePid.email
-                ))
+                is ThreePid.Email  -> identityAPI.requestTokenToBindEmail(
+                        IdentityRequestTokenForEmailBody(
+                                clientSecret = clientSecret,
+                                sendAttempt = sendAttempt,
+                                email = params.threePid.email
+                        )
+                )
                 is ThreePid.Msisdn -> {
-                    identityAPI.requestTokenToBindMsisdn(IdentityRequestTokenForMsisdnBody(
-                            clientSecret = clientSecret,
-                            sendAttempt = sendAttempt,
-                            phoneNumber = params.threePid.msisdn,
-                            countryCode = params.threePid.getCountryCode()
-                    ))
+                    identityAPI.requestTokenToBindMsisdn(
+                            IdentityRequestTokenForMsisdnBody(
+                                    clientSecret = clientSecret,
+                                    sendAttempt = sendAttempt,
+                                    phoneNumber = params.threePid.msisdn,
+                                    countryCode = params.threePid.getCountryCode()
+                            )
+                    )
                 }
             }
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentitySubmitTokenForBindingTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentitySubmitTokenForBindingTask.kt
index f884e2816dccfb9e3e63b572e1976b3a83f995cb..fcf8ce6317b93e20506ea782cd4bd912a9feb8ac 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentitySubmitTokenForBindingTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentitySubmitTokenForBindingTask.kt
@@ -50,7 +50,8 @@ internal class DefaultIdentitySubmitTokenForBindingTask @Inject constructor(
                             clientSecret = identityPendingBinding.clientSecret,
                             sid = identityPendingBinding.sid,
                             token = params.token
-                    ))
+                    )
+            )
         }
 
         if (!tokenResponse.isSuccess()) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityStore.kt
index 0e05224be5db88716aa025f39eb99a2345c08679..51d4ed7c6dde0b3a62550fe8c733f3b0f68897b8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityStore.kt
@@ -32,7 +32,7 @@ internal interface IdentityStore {
     fun setHashDetails(hashDetailResponse: IdentityHashDetailResponse)
 
     /**
-     * Store details about a current binding
+     * Store details about a current binding.
      */
     fun storePendingBinding(threePid: ThreePid, data: IdentityPendingBinding)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntityQuery.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntityQuery.kt
index 5152e33743640057512747a5796be732a65467e5..aecf21678c12576fff363146adc0bb39beb7818a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntityQuery.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntityQuery.kt
@@ -22,7 +22,7 @@ import io.realm.kotlin.createObject
 import io.realm.kotlin.where
 
 /**
- * Only one object can be stored at a time
+ * Only one object can be stored at a time.
  */
 internal fun IdentityDataEntity.Companion.get(realm: Realm): IdentityDataEntity? {
     return realm.where<IdentityDataEntity>().findFirst()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityRealmModule.kt
index 1f2cfad33c9b806bbe6fb1050f726a266b0869ed..a5ec6061ba68b2e9d5117c60c20ecb7bb459357b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityRealmModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityRealmModule.kt
@@ -19,11 +19,13 @@ package org.matrix.android.sdk.internal.session.identity.db
 import io.realm.annotations.RealmModule
 
 /**
- * Realm module for identity server classes
+ * Realm module for identity server classes.
  */
-@RealmModule(library = true,
+@RealmModule(
+        library = true,
         classes = [
             IdentityDataEntity::class,
             IdentityPendingBindingEntity::class
-        ])
+        ]
+)
 internal class IdentityRealmModule
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt
index 0c279d8a7ed80f42e8bc1df22e55f1f82d31eb41..e731f9f3472e473b810bba0c3b9be2bb05d02a30 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt
@@ -24,8 +24,8 @@ import javax.inject.Inject
 
 internal class RealmIdentityStoreMigration @Inject constructor() : RealmMigration {
     /**
-     * Forces all RealmIdentityStoreMigration instances to be equal
-     * Avoids Realm throwing when multiple instances of the migration are set
+     * Forces all RealmIdentityStoreMigration instances to be equal.
+     * Avoids Realm throwing when multiple instances of the migration are set.
      */
     override fun equals(other: Any?) = other is RealmIdentityStoreMigration
     override fun hashCode() = 3000
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/model/SignInvitationBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/model/SignInvitationBody.kt
index 699825726375ae1b5b0084ac953babbb291c0fc6..465d296e94515a902faf70dc859d86b3bd07cc07 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/model/SignInvitationBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/model/SignInvitationBody.kt
@@ -16,14 +16,16 @@
 
 package org.matrix.android.sdk.internal.session.identity.model
 
+import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 @JsonClass(generateAdapter = true)
 internal data class SignInvitationBody(
-        /**The Matrix user ID of the user accepting the invitation.*/
+        /** The Matrix user ID of the user accepting the invitation.*/
         val mxid: String,
-        /**The token from the call to store- invite..*/
+        /** The token from the call to store- invite..*/
         val token: String,
         /** The private key, encoded as Unpadded base64. */
-        val private_key: String
+        @Json(name = "private_key")
+        val privateKey: String
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/DefaultSyncStatusService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/DefaultSyncStatusService.kt
index c138c1a40e666ee5e4d687b8228bccc028cac72d..2aa0be80c9b4e36473adc2d433e517532b5a09c5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/DefaultSyncStatusService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/DefaultSyncStatusService.kt
@@ -41,7 +41,7 @@ internal class DefaultSyncStatusService @Inject constructor() :
     }
 
     /**
-     * Create a rootTask
+     * Create a rootTask.
      */
     fun startRoot(initSyncStep: InitSyncStep,
                   totalProgress: Int) {
@@ -51,7 +51,7 @@ internal class DefaultSyncStatusService @Inject constructor() :
     }
 
     /**
-     * Add a child to the leaf
+     * Add a child to the leaf.
      */
     override fun startTask(initSyncStep: InitSyncStep,
                            totalProgress: Int,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/TaskInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/TaskInfo.kt
index 3e4cce2e1fbbc79bbddf8ecebe2c246673ecb655..fef16bf1d773492b7054901a4101c41434bc7482 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/TaskInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/TaskInfo.kt
@@ -29,7 +29,7 @@ internal class TaskInfo(val initSyncStep: InitSyncStep,
     private val offset = parent?.currentProgress ?: 0F
 
     /**
-     * Get the further child
+     * Get the further child.
      */
     fun leaf(): TaskInfo {
         var last = this
@@ -40,7 +40,7 @@ internal class TaskInfo(val initSyncStep: InitSyncStep,
     }
 
     /**
-     * Set progress of this task and update the parent progress iteratively
+     * Set progress of this task and update the parent progress iteratively.
      */
     fun setProgress(progress: Float) {
         Timber.v("setProgress: $progress / $totalProgress")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/AllowedWidgetsContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/AllowedWidgetsContent.kt
index 8d0e8c930dc47acafdcced5bb76d6e9f5b171828..ebf14c602c587c867471eab7a47217c7b30186a1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/AllowedWidgetsContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/AllowedWidgetsContent.kt
@@ -22,18 +22,20 @@ import com.squareup.moshi.JsonClass
 @JsonClass(generateAdapter = true)
 internal data class AllowedWidgetsContent(
         /**
-         * Map of stateEventId to Allowed
+         * Map of stateEventId to Allowed.
          */
         @Json(name = "widgets") val widgets: Map<String, Boolean> = emptyMap(),
 
         /**
-         * Map of native widgetType to a map of domain to Allowed
+         * Map of native widgetType to a map of domain to Allowed.
+         * <pre>
          * {
          *      "jitsi" : {
          *            "jitsi.domain.org"  : true,
          *            "jitsi.other.org"  : false
          *      }
          * }
+         * </pre>
          */
         @Json(name = "native_widgets") val native: Map<String, Map<String, Boolean>> = emptyMap()
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt
index 1b96931c6c8eaeaf3155ed298d6f73fbc076baca..8034e5b9740632b1df5b272fa6fd44588300ef8a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt
@@ -124,7 +124,7 @@ internal class IntegrationManager @Inject constructor(matrixConfiguration: Matri
     }
 
     /**
-     * Returns false if the user as disabled integration manager feature
+     * Returns false if the user as disabled integration manager feature.
      */
     fun isIntegrationEnabled(): Boolean {
         val integrationProvisioningData = accountDataDataSource.getAccountDataEvent(UserAccountDataTypes.TYPE_INTEGRATION_PROVISIONING)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/PreviewUrlMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/PreviewUrlMapper.kt
index 551dc29b926d085a1f489bf298d01d148d844b97..06fbf802ae54dcd829020d895ea7d4cdcabe3a45 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/PreviewUrlMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/PreviewUrlMapper.kt
@@ -20,7 +20,7 @@ import org.matrix.android.sdk.api.session.media.PreviewUrlData
 import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntity
 
 /**
- * PreviewUrlCacheEntity -> PreviewUrlData
+ * PreviewUrlCacheEntity -> PreviewUrlData.
  */
 internal fun PreviewUrlCacheEntity.toDomain() = PreviewUrlData(
         url = urlFromServer ?: url,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt
index 0aeb0467de8ebf4ad3f7520448da03becb3a1baa..f9da7b66f623ff96a116637bc69697ab0fa5bd9a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt
@@ -126,7 +126,7 @@ internal class PermalinkFactory @Inject constructor(
     }
 
     /**
-     * Escape '/' in id, because it is used as a separator
+     * Escape '/' in id, because it is used as a separator.
      *
      * @param id the id to escape
      * @return the escaped id
@@ -136,7 +136,7 @@ internal class PermalinkFactory @Inject constructor(
     }
 
     /**
-     * Unescape '/' in id
+     * Unescape '/' in id.
      *
      * @param id the id to escape
      * @return the escaped id
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt
index d20cf8f140dd9d88594cc860c844d4c3ca16aa5a..0f667c65df7562390eeab67ac24f37c19c56edd3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt
@@ -68,7 +68,7 @@ internal class ViaParameterFinder @Inject constructor(
     }
 
     /**
-     * Get a set of userIds of joined members of a room
+     * Get a set of userIds of joined members of a room.
      */
     private fun getUserIdsOfJoinedMembers(roomId: String): Set<String> {
         return roomGetterProvider.get().getRoom(roomId)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/model/PresenceContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/model/PresenceContent.kt
index b1ca5126528f3a66af87f1d30d7a874ab7b254cd..abad91bad2f84900ecf270501fb915b6719ca157 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/model/PresenceContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/model/PresenceContent.kt
@@ -21,7 +21,7 @@ import com.squareup.moshi.JsonClass
 import org.matrix.android.sdk.api.session.presence.model.PresenceEnum
 
 /**
- * Class representing the EventType.PRESENCE event content
+ * Class representing the EventType.PRESENCE event content.
  */
 @JsonClass(generateAdapter = true)
 internal data class PresenceContent(
@@ -38,7 +38,7 @@ internal data class PresenceContent(
          */
         @Json(name = "status_msg") val statusMessage: String? = null,
         /**
-         * Whether the user is currently active
+         * Whether the user is currently active.
          */
         @Json(name = "currently_active") val isCurrentlyActive: Boolean = false,
         /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AccountThreePidsResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AccountThreePidsResponse.kt
index 0a792397f8e3699380953b7dd7dadeb9d73b3497..6d2b3c480d8f2387865beb0be9f0ddba17838ecd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AccountThreePidsResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AccountThreePidsResponse.kt
@@ -19,7 +19,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing the ThreePids response
+ * Class representing the ThreePids response.
  */
 @JsonClass(generateAdapter = true)
 internal data class AccountThreePidsResponse(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/BindThreePidsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/BindThreePidsTask.kt
index 87e51181e636952d757bb71c92607f06ef3b5447..f630c2c225fc355106eb018adb2ddb49d177f798 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/BindThreePidsTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/BindThreePidsTask.kt
@@ -50,7 +50,8 @@ internal class DefaultBindThreePidsTask @Inject constructor(private val profileA
                             identityServerUrlWithoutProtocol = identityServerUrlWithoutProtocol,
                             identityServerAccessToken = identityServerAccessToken,
                             sid = identityPendingBinding.sid
-                    ))
+                    )
+            )
         }
 
         // Binding is over, cleanup the store
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt
index 6f99577ac27c48d7ee8b0eb66b4d6b093ad90499..5e64a6af0e2bc568989b4c75eab6ca892be9afa9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt
@@ -135,21 +135,25 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
     override suspend fun finalizeAddingThreePid(threePid: ThreePid,
                                                 userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) {
         finalizeAddingThreePidTask
-                .execute(FinalizeAddingThreePidTask.Params(
-                        threePid = threePid,
-                        userInteractiveAuthInterceptor = userInteractiveAuthInterceptor,
-                        userWantsToCancel = false
-                ))
+                .execute(
+                        FinalizeAddingThreePidTask.Params(
+                                threePid = threePid,
+                                userInteractiveAuthInterceptor = userInteractiveAuthInterceptor,
+                                userWantsToCancel = false
+                        )
+                )
         refreshThreePids()
     }
 
     override suspend fun cancelAddingThreePid(threePid: ThreePid) {
         finalizeAddingThreePidTask
-                .execute(FinalizeAddingThreePidTask.Params(
-                        threePid = threePid,
-                        userInteractiveAuthInterceptor = null,
-                        userWantsToCancel = true
-                ))
+                .execute(
+                        FinalizeAddingThreePidTask.Params(
+                                threePid = threePid,
+                                userInteractiveAuthInterceptor = null,
+                                userWantsToCancel = true
+                        )
+                )
         refreshThreePids()
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt
index 4b56db9f1330cf999d5bcf6715c5bcbb1820d268..4d4506be76785f2d3365cabfd3848ad6c7f51d94 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt
@@ -46,7 +46,7 @@ internal interface ProfileAPI {
     suspend fun getThreePIDs(): AccountThreePidsResponse
 
     /**
-     * Change user display name
+     * Change user display name.
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}/displayname")
     suspend fun setDisplayName(@Path("userId") userId: String,
@@ -86,7 +86,7 @@ internal interface ProfileAPI {
     suspend fun addMsisdn(@Body body: AddMsisdnBody): AddMsisdnResponse
 
     /**
-     * Validate Msisdn code (same model than for identity server API)
+     * Validate Msisdn code (same model than for identity server API).
      */
     @POST
     suspend fun validateMsisdn(@Url url: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/UnbindThreePidsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/UnbindThreePidsTask.kt
index df8a1c97ffb5a29854d4af2cf9ad229a45e18797..acbecc9fbee766050e12bf6f5815eef7eddd6cc2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/UnbindThreePidsTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/UnbindThreePidsTask.kt
@@ -45,7 +45,8 @@ internal class DefaultUnbindThreePidsTask @Inject constructor(private val profil
                             identityServerUrlWithoutProtocol,
                             params.threePid.toMedium(),
                             params.threePid.value
-                    ))
+                    )
+            )
         }.isSuccess()
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultPushersService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultPushersService.kt
index e87c27e601573e5e6a97cba49b238473a58d87bd..13b990a9ff5baeb0135c634d9ed156726535d7a8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultPushersService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultPushersService.kt
@@ -85,17 +85,19 @@ internal class DefaultPushersService @Inject constructor(
                                         deviceDisplayName: String,
                                         append: Boolean) {
         addPusherTask.execute(
-                AddPusherTask.Params(JsonPusher(
-                        pushKey = email,
-                        kind = Pusher.KIND_EMAIL,
-                        appId = Pusher.APP_ID_EMAIL,
-                        profileTag = "",
-                        lang = lang,
-                        appDisplayName = appDisplayName,
-                        deviceDisplayName = deviceDisplayName,
-                        data = JsonPusherData(brand = emailBranding),
-                        append = append
-                ))
+                AddPusherTask.Params(
+                        JsonPusher(
+                                pushKey = email,
+                                kind = Pusher.KIND_EMAIL,
+                                appId = Pusher.APP_ID_EMAIL,
+                                profileTag = "",
+                                lang = lang,
+                                appDisplayName = appDisplayName,
+                                deviceDisplayName = deviceDisplayName,
+                                data = JsonPusherData(brand = emailBranding),
+                                append = append
+                        )
+                )
         )
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesResponse.kt
index de038196291efb2aca738291d6486cf9e2e09399..5f35c919fc021caab4e267874cd54ff3d29a6866 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesResponse.kt
@@ -26,13 +26,13 @@ import org.matrix.android.sdk.api.session.pushrules.rest.RuleSet
 @JsonClass(generateAdapter = true)
 internal data class GetPushRulesResponse(
         /**
-         * Global rules, account level applying to all devices
+         * Global rules, account level applying to all devices.
          */
         @Json(name = "global")
         val global: RuleSet,
 
         /**
-         * Device specific rules, apply only to current device
+         * Device specific rules, apply only to current device.
          */
         @Json(name = "device")
         val device: RuleSet? = null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesTask.kt
index 8cf861d2853c88dc769cc0d76b31916cb4a9463f..8e7078292bd0b46a43f802afe9e555dce26faffa 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushRulesTask.kt
@@ -25,7 +25,7 @@ internal interface GetPushRulesTask : Task<GetPushRulesTask.Params, Unit> {
 }
 
 /**
- * We keep this task, but it should not be used anymore, the push rules comes from the sync response
+ * We keep this task, but it should not be used anymore, the push rules comes from the sync response.
  */
 internal class DefaultGetPushRulesTask @Inject constructor(
         private val pushRulesApi: PushRulesApi,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/JsonPusher.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/JsonPusher.kt
index 8dc0954694c8e1a3a9bdd59eaa01695cf6f53d15..71a1ea8c6669471d191b44c8c2e068c6c186d8ef 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/JsonPusher.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/JsonPusher.kt
@@ -22,7 +22,6 @@ import java.security.InvalidParameterException
 
 /**
  * Example:
- *
  * <code>
  *     {
  *      "pushers": [
@@ -40,6 +39,7 @@ import java.security.InvalidParameterException
  *      }]
  *  }
  * </code>
+ * .
  */
 @JsonClass(generateAdapter = true)
 internal data class JsonPusher(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushRulesApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushRulesApi.kt
index dab6d373177b9f26062c70048d5be00c8a710633..40b4ee269ac8b3d82318f5c6c1e52af2438be1b1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushRulesApi.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushRulesApi.kt
@@ -25,13 +25,13 @@ import retrofit2.http.Path
 
 internal interface PushRulesApi {
     /**
-     * Get all push rules
+     * Get all push rules.
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/")
     suspend fun getAllRules(): GetPushRulesResponse
 
     /**
-     * Update the ruleID enable status
+     * Update the ruleID enable status.
      *
      * @param kind   the notification kind (sender, room...)
      * @param ruleId the ruleId
@@ -43,7 +43,7 @@ internal interface PushRulesApi {
                                        @Body enabledBody: EnabledBody)
 
     /**
-     * Update the ruleID action
+     * Update the ruleID action.
      * Ref: https://matrix.org/docs/spec/client_server/latest#put-matrix-client-r0-pushrules-scope-kind-ruleid-actions
      *
      * @param kind    the notification kind (sender, room...)
@@ -56,7 +56,7 @@ internal interface PushRulesApi {
                                   @Body actions: Any)
 
     /**
-     * Delete a rule
+     * Delete a rule.
      *
      * @param kind   the notification kind (sender, room...)
      * @param ruleId the ruleId
@@ -66,7 +66,7 @@ internal interface PushRulesApi {
                            @Path("ruleId") ruleId: String)
 
     /**
-     * Add the ruleID enable status
+     * Add the ruleID enable status.
      *
      * @param kind   the notification kind (sender, room...)
      * @param ruleId the ruleId.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/SavePushRulesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/SavePushRulesTask.kt
index ff685e9281554754fe04128c17bd73e2aeeaaa4a..88c78aa460e335cf8ce115f9bb3769d2131ab881 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/SavePushRulesTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/SavePushRulesTask.kt
@@ -27,7 +27,7 @@ import org.matrix.android.sdk.internal.util.awaitTransaction
 import javax.inject.Inject
 
 /**
- * Save the push rules in DB
+ * Save the push rules in DB.
  */
 internal interface SavePushRulesTask : Task<SavePushRulesTask.Params, Unit> {
     data class Params(val pushRules: GetPushRulesResponse)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt
index 91d092a2b4b552f9b2e1185f01d24a1fb07edbe3..60c1194708307859e2060ae2d42251f8d540d042 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt
@@ -67,8 +67,10 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
         }.filter {
             it.senderId != userId
         }
-        Timber.v("[PushRules] Found ${allEvents.size} out of ${(newJoinEvents + inviteEvents).size}" +
-                " to check for push rules with ${params.rules.size} rules")
+        Timber.v(
+                "[PushRules] Found ${allEvents.size} out of ${(newJoinEvents + inviteEvents).size}" +
+                        " to check for push rules with ${params.rules.size} rules"
+        )
         val matchedEvents = allEvents.mapNotNull { event ->
             pushRuleFinder.fulfilledBingRule(event, params.rules)?.let {
                 Timber.v("[PushRules] Rule $it match for event ${event.eventId}")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt
index 7e0b44a3149fd0bce90e99f1f049c8dc016ec5d2..16a63a9a96afb152dee055d4b9e3cb74ae5473dc 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt
@@ -372,7 +372,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
     }
 
     /**
-     * Check if the edition is on the latest thread event, and update it accordingly
+     * Check if the edition is on the latest thread event, and update it accordingly.
      * @param editedEvent The event that will be changed
      * @param replaceEvent The new event
      */
@@ -651,7 +651,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
     }
 
     /**
-     * Called when an event is deleted
+     * Called when an event is deleted.
      */
     private fun handleRedactionOfReplace(realm: Realm,
                                          redacted: EventEntity,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt
index 65ef94999fc2e79b43aeda24cd56f79d987f0c0f..72f56ddf688524128ec8a77b13b04daa8315f1b4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt
@@ -92,7 +92,7 @@ internal interface RoomAPI {
     ): PaginationResponse
 
     /**
-     * Get all members of a room
+     * Get all members of a room.
      *
      * @param roomId        the room id where to get the members
      * @param syncToken     the sync token (optional)
@@ -136,7 +136,7 @@ internal interface RoomAPI {
                                   @Query("filter") filter: String? = null): EventContextResponse
 
     /**
-     * Retrieve an event from its room id / events id
+     * Retrieve an event from its room id / events id.
      *
      * @param roomId  the room id
      * @param eventId the event Id
@@ -156,7 +156,7 @@ internal interface RoomAPI {
                                @Body markers: Map<String, String>)
 
     /**
-     * Send receipt to a room
+     * Send receipt to a room.
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/receipt/{receiptType}/{eventId}")
     suspend fun sendReceipt(@Path("roomId") roomId: String,
@@ -185,7 +185,7 @@ internal interface RoomAPI {
                            @Body body: ThreePidInviteBody)
 
     /**
-     * Send a generic state event
+     * Send a generic state event.
      *
      * @param roomId         the room id.
      * @param stateEventType the state event type
@@ -198,7 +198,7 @@ internal interface RoomAPI {
     ): SendResponse
 
     /**
-     * Send a generic state event
+     * Send a generic state event.
      *
      * @param roomId         the room id.
      * @param stateEventType the state event type
@@ -220,7 +220,7 @@ internal interface RoomAPI {
     suspend fun getRoomState(@Path("roomId") roomId: String): List<Event>
 
     /**
-     * Paginate relations for event based in normal topological order
+     * Paginate relations for event based in normal topological order.
      * @param relationType filter for this relation type
      * @param eventType filter for this event type
      */
@@ -235,7 +235,7 @@ internal interface RoomAPI {
     ): RelationsResponse
 
     /**
-     * Paginate relations for thread events based in normal topological order
+     * Paginate relations for thread events based in normal topological order.
      * @param relationType filter for this relation type
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "rooms/{roomId}/relations/{eventId}/{relationType}")
@@ -337,14 +337,14 @@ internal interface RoomAPI {
     suspend fun getAliases(@Path("roomId") roomId: String): GetAliasesResponse
 
     /**
-     * Inform that the user is starting to type or has stopped typing
+     * Inform that the user is starting to type or has stopped typing.
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/typing/{userId}")
     suspend fun sendTypingState(@Path("roomId") roomId: String,
                                 @Path("userId") userId: String,
                                 @Body body: TypingBody)
 
-    /**
+    /*
      * Room tagging
      */
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAvatarResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAvatarResolver.kt
index 60ad83ee055ebc668b1e7047138c33c8f4b08b36..29a303475bc17898db0d108dad2498e0de0af3dd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAvatarResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAvatarResolver.kt
@@ -34,7 +34,7 @@ import javax.inject.Inject
 internal class RoomAvatarResolver @Inject constructor(@UserId private val userId: String) {
 
     /**
-     * Compute the room avatar url
+     * Compute the room avatar url.
      * @param realm: the current instance of realm
      * @param roomId the roomId of the room to resolve avatar
      * @return the room avatar url, can be a fallback to a room member avatar or null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt
index 5e90076b8af24fb73116c5d52fc9af1830cd56dc..f3845f1f15c93911224c72b339367387088912a6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt
@@ -108,14 +108,14 @@ import retrofit2.Retrofit
 import javax.inject.Qualifier
 
 /**
- * Used to inject the simple commonmark Parser
+ * Used to inject the simple commonmark Parser.
  */
 @Qualifier
 @Retention(AnnotationRetention.RUNTIME)
 internal annotation class SimpleCommonmarkParser
 
 /**
- * Used to inject the advanced commonmark Parser
+ * Used to inject the advanced commonmark Parser.
  */
 @Qualifier
 @Retention(AnnotationRetention.RUNTIME)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt
index 69352688e3b74382804011f01d9c49fb745ad8b2..cffa632768ca7f2e3fbc02645fa56c8f721877a8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt
@@ -25,7 +25,7 @@ import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
 import org.matrix.android.sdk.internal.session.room.membership.threepid.ThreePidInviteBody
 
 /**
- * Parameter to create a room
+ * Parameter to create a room.
  */
 @JsonClass(generateAdapter = true)
 internal data class CreateRoomBody(
@@ -108,7 +108,7 @@ internal data class CreateRoomBody(
         val isDirect: Boolean?,
 
         /**
-         * The power level content to override in the default power level event
+         * The power level content to override in the default power level event.
          */
         @Json(name = "power_level_content_override")
         val powerLevelContentOverride: PowerLevelsContent?,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
index 3b2e9d3d2287515dc5796498b611178cf4d82466..faf68d538fd9d8fd52f650a9e040564dfcad826a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
@@ -116,7 +116,8 @@ internal class CreateRoomBodyBuilder @Inject constructor(
                 fileUploader.uploadFromUri(
                         uri = avatarUri,
                         filename = UUID.randomUUID().toString(),
-                        mimeType = MimeTypes.Jpeg)
+                        mimeType = MimeTypes.Jpeg
+                )
             }
         }?.let { response ->
             Event(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt
index bd9f2ecc36791a67242de1a5d9d010ee953498e1..59e0f81ece88e81435d1c866b77f492d27782104 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt
@@ -38,7 +38,7 @@ import org.matrix.android.sdk.internal.util.Normalizer
 import javax.inject.Inject
 
 /**
- * This class computes room display name
+ * This class computes room display name.
  */
 internal class RoomDisplayNameResolver @Inject constructor(
         matrixConfiguration: MatrixConfiguration,
@@ -50,7 +50,7 @@ internal class RoomDisplayNameResolver @Inject constructor(
     private val roomDisplayNameFallbackProvider = matrixConfiguration.roomDisplayNameFallbackProvider
 
     /**
-     * Compute the room display name
+     * Compute the room display name.
      *
      * @param realm: the current instance of realm
      * @param roomId: the roomId to resolve the name of.
@@ -157,7 +157,7 @@ internal class RoomDisplayNameResolver @Inject constructor(
         return (name ?: roomId).toRoomName()
     }
 
-    /** See [org.matrix.android.sdk.api.session.room.sender.SenderInfo.disambiguatedDisplayName] */
+    /** See [org.matrix.android.sdk.api.session.room.sender.SenderInfo.disambiguatedDisplayName]. */
     private fun resolveRoomMemberName(roomMemberSummary: RoomMemberSummaryEntity,
                                       roomMemberHelper: RoomMemberHelper): String {
         val isUnique = roomMemberHelper.isUniqueDisplayName(roomMemberSummary.displayName)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt
index 85300fa3518de924f1e6dbf3b108ecb56b7e0951..a1b30a0be562756ebec3d617f9e3b9119ad02305 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt
@@ -83,7 +83,8 @@ internal class RoomMemberEventHandler @Inject constructor(
                 roomMember,
                 // When an update is happening, insertOrUpdate replace existing values with null if they are not provided,
                 // but we want to preserve presence record value and not replace it with null
-                getExistingPresenceState(realm, roomId, userId))
+                getExistingPresenceState(realm, roomId, userId)
+        )
         realm.insertOrUpdate(roomMemberEntity)
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberHelper.kt
index 9ce8db25a5bec865c4412bc7d7c257b096f94e6d..40228fe8c977a1f4372b6dca04d23ed02cde8a59 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberHelper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberHelper.kt
@@ -104,7 +104,7 @@ internal class RoomMemberHelper(private val realm: Realm,
     }
 
     /**
-     * Return all the roomMembers ids which are joined or invited to the room
+     * Return all the roomMembers ids which are joined or invited to the room.
      *
      * @return a roomMember id list of joined or invited members.
      */
@@ -113,7 +113,7 @@ internal class RoomMemberHelper(private val realm: Realm,
     }
 
     /**
-     * Return all the roomMembers ids which are joined to the room
+     * Return all the roomMembers ids which are joined to the room.
      *
      * @return a roomMember id list of joined members.
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/JoinRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/JoinRoomTask.kt
index 6306f3c6fee3b8a126d5e7cea13ae2fabbfc22c2..4c631c2182733ba966a0e211bafab0ff6c142be1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/JoinRoomTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/joining/JoinRoomTask.kt
@@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.room.membership.joining
 
 import io.realm.RealmConfiguration
 import kotlinx.coroutines.TimeoutCancellationException
+import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
 import org.matrix.android.sdk.api.session.events.model.toContent
 import org.matrix.android.sdk.api.session.identity.model.SignInvitationResult
 import org.matrix.android.sdk.api.session.room.failure.JoinRoomFailure
@@ -53,6 +54,7 @@ internal class DefaultJoinRoomTask @Inject constructor(
         private val readMarkersTask: SetReadMarkersTask,
         @SessionDatabase
         private val realmConfiguration: RealmConfiguration,
+        private val coroutineDispatcher: MatrixCoroutineDispatchers,
         private val roomChangeMembershipStateDataSource: RoomChangeMembershipStateDataSource,
         private val globalErrorReceiver: GlobalErrorReceiver,
         private val clock: Clock,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/prune/RedactionEventProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/prune/RedactionEventProcessor.kt
index fe7dc28228eda5f39c0a90885d4234b1734df0f1..e926d6a785ab1b859508f5310fe50091fb5c2722 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/prune/RedactionEventProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/prune/RedactionEventProcessor.kt
@@ -148,7 +148,8 @@ internal class RedactionEventProcessor @Inject constructor() : EventInsertLivePr
             EventType.STATE_ROOM_MEMBER          -> listOf("membership")
             EventType.STATE_ROOM_CREATE          -> listOf("creator")
             EventType.STATE_ROOM_JOIN_RULES      -> listOf("join_rule")
-            EventType.STATE_ROOM_POWER_LEVELS    -> listOf("users",
+            EventType.STATE_ROOM_POWER_LEVELS    -> listOf(
+                    "users",
                     "users_default",
                     "events",
                     "events_default",
@@ -156,7 +157,8 @@ internal class RedactionEventProcessor @Inject constructor() : EventInsertLivePr
                     "ban",
                     "kick",
                     "redact",
-                    "invite")
+                    "invite"
+            )
             EventType.STATE_ROOM_ALIASES         -> listOf("aliases")
             EventType.STATE_ROOM_CANONICAL_ALIAS -> listOf("alias")
             EventType.FEEDBACK                   -> listOf("type", "target_event_id")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt
index ab514d31c8480951f7ff567eb803562566aba1e8..7b68e2a74c1b3b1efe728301bb65f4fcdcee05e9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt
@@ -131,7 +131,8 @@ internal class DefaultRelationService @AssistedInject constructor(
                 replyText = replyText,
                 autoMarkdown = autoMarkdown,
                 rootThreadEventId = rootThreadEventId,
-                showInThread = showInThread)
+                showInThread = showInThread
+        )
                 ?.also { saveLocalEcho(it) }
                 ?: return null
 
@@ -186,7 +187,8 @@ internal class DefaultRelationService @AssistedInject constructor(
                     text = replyInThreadText,
                     msgType = msgType,
                     autoMarkdown = autoMarkdown,
-                    formattedText = formattedText)
+                    formattedText = formattedText
+            )
                     .also {
                         saveLocalEcho(it)
                     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt
index 8d35a8fea4cb4fec267ee82051fa85baa78d9f33..dabdd04f60205d9e3b0c986489817e043d92c036 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt
@@ -192,7 +192,7 @@ internal class DefaultFetchThreadTimelineTask @Inject constructor(
 
     // TODO Reuse this function to all the app
     /**
-     * If we don't have any new state on this user, get it from db
+     * If we don't have any new state on this user, get it from db.
      */
     private fun HashMap<String, RoomMemberContent?>.addSenderState(realm: Realm, roomId: String, senderId: String) {
         getOrPut(senderId) {
@@ -204,7 +204,7 @@ internal class DefaultFetchThreadTimelineTask @Inject constructor(
     }
 
     /**
-     * Create an EventEntity to be added in the TimelineEventEntity
+     * Create an EventEntity to be added in the TimelineEventEntity.
      */
     private fun createEventEntity(roomId: String, event: Event, realm: Realm): EventEntity {
         val ageLocalTs = event.unsignedData?.age?.let { clock.epochMillis() - it }
@@ -212,7 +212,7 @@ internal class DefaultFetchThreadTimelineTask @Inject constructor(
     }
 
     /**
-     * Invoke the event decryption mechanism for a specific event
+     * Invoke the event decryption mechanism for a specific event.
      */
     private suspend fun decryptIfNeeded(event: Event, roomId: String) {
         try {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt
index 34e38581d1fc0ccd2710387c46b7b2f598fa43e0..8529365858e6bbaeaf34b4b1070ca18645287cde 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt
@@ -275,7 +275,8 @@ internal class DefaultSendService @AssistedInject constructor(
                     attachment = it,
                     compressBeforeSending = compressBeforeSending,
                     roomIds = roomIds,
-                    rootThreadEventId = rootThreadEventId)
+                    rootThreadEventId = rootThreadEventId
+            )
         }
     }
 
@@ -297,7 +298,8 @@ internal class DefaultSendService @AssistedInject constructor(
             localEchoEventFactory.createMediaEvent(
                     roomId = it,
                     attachment = attachment,
-                    rootThreadEventId = rootThreadId).also { event ->
+                    rootThreadEventId = rootThreadId
+            ).also { event ->
                 createLocalEcho(event)
             }
         }
@@ -305,7 +307,7 @@ internal class DefaultSendService @AssistedInject constructor(
     }
 
     /**
-     * We use the roomId of the local echo event
+     * We use the roomId of the local echo event.
      */
     private fun internalSendMedia(allLocalEchoes: List<Event>, attachment: ContentAttachmentData, compressBeforeSending: Boolean): Cancelable {
         val cancelableBag = CancelableBag()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt
index d019ffada62a2a6815b13eb72014314b746fe25a..d39088bd6dc54758b7449d1880b481504b89afbe 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt
@@ -506,7 +506,7 @@ internal class LocalEchoEventFactory @Inject constructor(
     }
 
     /**
-     * Enhance sticker to support threads fallback if needed
+     * Enhance sticker to support threads fallback if needed.
      */
     private fun enhanceStickerIfNeeded(type: String, content: Content?): Content? {
         var newContent: Content? = null
@@ -526,7 +526,7 @@ internal class LocalEchoEventFactory @Inject constructor(
     }
 
     /**
-     * Creates a thread event related to the already existing root event
+     * Creates a thread event related to the already existing root event.
      */
     fun createThreadTextEvent(
             rootThreadEventId: String,
@@ -553,7 +553,7 @@ internal class LocalEchoEventFactory @Inject constructor(
     }
 
     /**
-     * Creates a reply to a regular timeline Event or a thread Event if needed
+     * Creates a reply to a regular timeline Event or a thread Event if needed.
      */
     fun createReplyTextEvent(roomId: String,
                              eventReplied: TimelineEvent,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt
index 9fd45b917fa28f3a0df38abb6994f57de30c4043..bed590fd09816e683f0ed37738ef205813b04f75 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt
@@ -221,7 +221,7 @@ internal class LocalEchoRepository @Inject constructor(
     }
 
     /**
-     * Returns the latest known thread event message, or the rootThreadEventId if no other event found
+     * Returns the latest known thread event message, or the rootThreadEventId if no other event found.
      */
     fun getLatestThreadEvent(rootThreadEventId: String): String {
         return realmSessionProvider.withRealm { realm ->
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParser.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParser.kt
index 05585a4cb5c6c138963fa993a65ad10a0a90ac51..6a9f86893f005fad2c1f8996f508b17d27fb5f38 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParser.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParser.kt
@@ -78,7 +78,7 @@ internal class MarkdownParser @Inject constructor(
             text != htmlText && htmlText != "<p>${text.trim()}</p>\n"
 
     /**
-     * The parser makes some mistakes, so deal with it here
+     * The parser makes some mistakes, so deal with it here.
      */
     private fun String.postTreatment(): String {
         return this
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt
index ecc81492554838d1fdbebb1757003db4bc65dce3..2afca6e554a76d92be906640db22dc5787e9b7f8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt
@@ -33,10 +33,10 @@ import timber.log.Timber
 import javax.inject.Inject
 
 /**
- * This worker creates a new work for each events passed in parameter
+ * This worker creates a new work for each events passed in parameter.
  *
- * Possible previous worker: Always [UploadContentWorker]
- * Possible next worker    : None, but it will post new work to send events, encrypted or not
+ * Possible previous worker: Always [UploadContentWorker].
+ * Possible next worker    : None, but it will post new work to send events, encrypted or not.
  */
 internal class MultipleEventSendingDispatcherWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
         SessionSafeCoroutineWorker<MultipleEventSendingDispatcherWorker.Params>(context, params, sessionManager, Params::class.java) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/NoMerger.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/NoMerger.kt
index b56b2831714160eff582b877589daa6312a33547..6dbd8682d79dd58011f37e8b943a8316c6be1a40 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/NoMerger.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/NoMerger.kt
@@ -19,7 +19,7 @@ import androidx.work.Data
 import androidx.work.InputMerger
 
 /**
- * InputMerger which takes only the first input, to ensure an appended work will only have the specified parameters
+ * InputMerger which takes only the first input, to ensure an appended work will only have the specified parameters.
  */
 internal class NoMerger : InputMerger() {
     override fun merge(inputs: MutableList<Data>): Data {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt
index 83c61d28451b3718b190264df985d659e0c5bda7..1c0da4839ab64b3be55b7309c9f504ad55ad6169 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt
@@ -30,8 +30,8 @@ import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
 import javax.inject.Inject
 
 /**
- * Possible previous worker: None
- * Possible next worker    : None
+ * Possible previous worker: None.
+ * Possible next worker    : None.
  */
 internal class RedactEventWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
         SessionSafeCoroutineWorker<RedactEventWorker.Params>(context, params, sessionManager, Params::class.java) {
@@ -74,9 +74,13 @@ internal class RedactEventWorker(context: Context, params: WorkerParameters, ses
                         else                         -> {
                             // TODO mark as failed to send?
                             // always return success, or the chain will be stuck for ever!
-                            Result.success(WorkerParamsFactory.toData(params.copy(
-                                    lastFailureMessage = it.localizedMessage
-                            )))
+                            Result.success(
+                                    WorkerParamsFactory.toData(
+                                            params.copy(
+                                                    lastFailureMessage = it.localizedMessage
+                                            )
+                                    )
+                            )
                         }
                     }
                 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt
index ddbe8a61a0f0ef4a45a52933a2a5c8e9a41f824f..bea6069dd69fae281c1313cd2aca4a732c671293 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt
@@ -36,8 +36,8 @@ import javax.inject.Inject
 // private const val MAX_NUMBER_OF_RETRY_BEFORE_FAILING = 3
 
 /**
- * Possible previous worker: [EncryptEventWorker] or first worker
- * Possible next worker    : None
+ * Possible previous worker: [EncryptEventWorker] or first worker.
+ * Possible next worker    : None.
  */
 internal class SendEventWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
         SessionSafeCoroutineWorker<SendEventWorker.Params>(context, params, sessionManager, Params::class.java) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/TextContentExtension.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/TextContentExtension.kt
index 8caa99d90a25798af721958d9d73099f17582215..49bc05f40c92f632b5bd6eff298542f576981b8c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/TextContentExtension.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/TextContentExtension.kt
@@ -54,7 +54,8 @@ internal fun TextContent.toThreadTextContent(
                     isFallingBack = true,
                     inReplyTo = ReplyToContent(
                             eventId = latestThreadEventId
-                    )),
+                    )
+            ),
             formattedBody = formattedText
     )
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt
index a1d3e2c0ac45ea670c85a38cf2f065e6c464cb24..8ef631ad36a499f148fe0c23f0e8b8d5b4ef1ae0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt
@@ -64,12 +64,12 @@ internal class EventSenderProcessorCoroutine @Inject constructor(
     private val waitForNetworkSequencer = SemaphoreCoroutineSequencer()
 
     /**
-     * sequencers use QueuedTask.queueIdentifier as key
+     * sequencers use QueuedTask.queueIdentifier as key.
      */
     private val sequencers = ConcurrentHashMap<String, CoroutineSequencer>()
 
     /**
-     * cancelableBag use QueuedTask.taskIdentifier as key
+     * cancelableBag use QueuedTask.taskIdentifier as key.
      */
     private val cancelableBag = ConcurrentHashMap<String, Cancelable>()
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/TaskInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/TaskInfo.kt
index a03ab778f68ca6980454402350094244b8dd1e64..e216e5109fc22c397d85d51f16c4fed5a30da265 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/TaskInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/TaskInfo.kt
@@ -24,8 +24,8 @@ import org.matrix.android.sdk.internal.di.SerializeNulls
 import org.matrix.android.sdk.internal.network.parsing.RuntimeJsonAdapterFactory
 
 /**
- * Info that need to be persisted by the sender thread
- * With polymorphic moshi parsing
+ * Info that need to be persisted by the sender thread.
+ * With polymorphic moshi parsing.
  */
 internal interface TaskInfo {
     val type: String
@@ -37,9 +37,10 @@ internal interface TaskInfo {
         const val TYPE_REDACT = "TYPE_REDACT"
 
         private val moshi = Moshi.Builder()
-                .add(RuntimeJsonAdapterFactory.of(TaskInfo::class.java, "type", FallbackTaskInfo::class.java)
-                        .registerSubtype(SendEventTaskInfo::class.java, TYPE_SEND)
-                        .registerSubtype(RedactEventTaskInfo::class.java, TYPE_REDACT)
+                .add(
+                        RuntimeJsonAdapterFactory.of(TaskInfo::class.java, "type", FallbackTaskInfo::class.java)
+                                .registerSubtype(SendEventTaskInfo::class.java, TYPE_SEND)
+                                .registerSubtype(RedactEventTaskInfo::class.java, TYPE_REDACT)
                 )
                 .add(SerializeNulls.JSON_ADAPTER_FACTORY)
                 .build()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt
index e5c7a75cb6bd19e7ccf66e171344c91bc059972d..60231892e104ddf9ef784d0a5bfd18bba898aeae 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt
@@ -136,7 +136,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
         if (joinRules != null) {
             val body = if (joinRules == RoomJoinRules.RESTRICTED) {
                 RoomJoinRulesContent(
-                        _joinRules = RoomJoinRules.RESTRICTED.value,
+                        joinRulesStr = RoomJoinRules.RESTRICTED.value,
                         allowList = allowList
                 ).toContent()
             } else {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt
index 1f2ec09367d4c996c70445b6dab0a27bf9ff3181..b0c795950e276fd5ea19ec4aadbd6f7bf062a1f1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/SafePowerLevelContent.kt
@@ -23,8 +23,11 @@ import org.matrix.android.sdk.api.session.events.model.toModel
 import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
 import org.matrix.android.sdk.api.util.JsonDict
 
+/**
+ * Serializable object.
+ */
 @JsonClass(generateAdapter = true)
-internal data class SerializablePowerLevelsContent(
+internal data class SafePowerLevelContent(
         @Json(name = "ban") val ban: Int?,
         @Json(name = "kick") val kick: Int?,
         @Json(name = "invite") val invite: Int?,
@@ -41,7 +44,7 @@ internal data class SerializablePowerLevelsContent(
 internal fun JsonDict.toSafePowerLevelsContentDict(): JsonDict {
     return toModel<PowerLevelsContent>()
             ?.let { content ->
-                SerializablePowerLevelsContent(
+                SafePowerLevelContent(
                         ban = content.ban,
                         kick = content.kick,
                         invite = content.invite,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/GraphUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/GraphUtils.kt
index 52879d71219264e422502d08e3dab0f163e54566..496bc7097fe1e6b910e50d47bf9d81778e4320a2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/GraphUtils.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/GraphUtils.kt
@@ -71,7 +71,7 @@ internal class Graph {
     }
 
     /**
-     * Depending on the chosen starting point the background edge might change
+     * Depending on the chosen starting point the background edge might change.
      */
     fun findBackwardEdges(startFrom: GraphNode? = null): List<GraphEdge> {
         val backwardEdges = mutableSetOf<GraphEdge>()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
index 3af579d0507bed867b1dfb4c448d7d11c604d333..611d6dc65e7a84b70885ab60eb21d92962fb613e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
@@ -212,7 +212,7 @@ internal class RoomSummaryUpdater @Inject constructor(
     }
 
     /**
-     * Should be called at the end of the room sync, to check and validate all parent/child relations
+     * Should be called at the end of the room sync, to check and validate all parent/child relations.
      */
     fun validateSpaceRelationship(realm: Realm) {
         measureTimeMillis {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/threads/DefaultThreadsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/threads/DefaultThreadsService.kt
index b65991347dd3693edab907d8c211243e3c72c544..6c6d6368d1ab775f8d6d9ac17b0c2b03ef6b717f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/threads/DefaultThreadsService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/threads/DefaultThreadsService.kt
@@ -72,17 +72,21 @@ internal class DefaultThreadsService @AssistedInject constructor(
     }
 
     override suspend fun fetchThreadTimeline(rootThreadEventId: String, from: String, limit: Int) {
-        fetchThreadTimelineTask.execute(FetchThreadTimelineTask.Params(
-                roomId = roomId,
-                rootThreadEventId = rootThreadEventId,
-                from = from,
-                limit = limit
-        ))
+        fetchThreadTimelineTask.execute(
+                FetchThreadTimelineTask.Params(
+                        roomId = roomId,
+                        rootThreadEventId = rootThreadEventId,
+                        from = from,
+                        limit = limit
+                )
+        )
     }
 
     override suspend fun fetchThreadSummaries() {
-        fetchThreadSummariesTask.execute(FetchThreadSummariesTask.Params(
-                roomId = roomId
-        ))
+        fetchThreadSummariesTask.execute(
+                FetchThreadSummariesTask.Params(
+                        roomId = roomId
+                )
+        )
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/threads/local/DefaultThreadsLocalService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/threads/local/DefaultThreadsLocalService.kt
index 3bc36fb2a804c8b9dfc0452a1f63d5a3e774dfbf..296981dfc8e7097efb3da70ed96928762bad7c6c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/threads/local/DefaultThreadsLocalService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/threads/local/DefaultThreadsLocalService.kt
@@ -83,7 +83,8 @@ internal class DefaultThreadsLocalService @AssistedInject constructor(
                     realm = it,
                     roomId = roomId,
                     rootThreadEventId = rootThreadEventId,
-                    senderId = userId)
+                    senderId = userId
+            )
         }
     }
 
@@ -97,7 +98,8 @@ internal class DefaultThreadsLocalService @AssistedInject constructor(
         monarchy.awaitTransaction {
             EventEntity.where(
                     realm = it,
-                    eventId = rootThreadEventId).findFirst()?.threadNotificationState = ThreadNotificationState.NO_NEW_MESSAGE
+                    eventId = rootThreadEventId
+            ).findFirst()?.threadNotificationState = ThreadNotificationState.NO_NEW_MESSAGE
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt
index 18fbe73c098e58b831eed28eb4caacd2df24e9e9..fad21c09180f9a3e8d9c9061f5201368408453e9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt
@@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.settings.LightweightSettingsStorage
 import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper
 import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask
 import org.matrix.android.sdk.internal.session.room.relation.threads.FetchThreadTimelineTask
+import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
 import org.matrix.android.sdk.internal.session.sync.handler.room.ReadReceiptHandler
 import org.matrix.android.sdk.internal.session.sync.handler.room.ThreadsAwarenessHandler
 import org.matrix.android.sdk.internal.task.SemaphoreCoroutineSequencer
@@ -59,6 +60,7 @@ internal class DefaultTimeline(
         private val settings: TimelineSettings,
         private val coroutineDispatchers: MatrixCoroutineDispatchers,
         private val clock: Clock,
+        stateEventDataSource: StateEventDataSource,
         paginationTask: PaginationTask,
         getEventTask: GetContextOfEventTask,
         fetchTokenAndPaginateTask: FetchTokenAndPaginateTask,
@@ -106,7 +108,9 @@ internal class DefaultTimeline(
             onEventsUpdated = this::sendSignalToPostSnapshot,
             onEventsDeleted = this::onEventsDeleted,
             onLimitedTimeline = this::onLimitedTimeline,
-            onNewTimelineEvents = this::onNewTimelineEvents
+            onNewTimelineEvents = this::onNewTimelineEvents,
+            stateEventDataSource = stateEventDataSource,
+            matrixCoroutineDispatchers = coroutineDispatchers,
     )
 
     private var strategy: LoadTimelineStrategy = buildStrategy(LoadTimelineStrategy.Mode.Live)
@@ -291,7 +295,6 @@ internal class DefaultTimeline(
         }
     }
 
-    @Suppress("EXPERIMENTAL_API_USAGE")
     private fun listenToPostSnapshotSignals() {
         postSnapshotSignalFlow
                 .sample(150)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt
index 849d7bd7ab6b195b244b3173dbec48a4a5757620..53c025387668a2cd3d5fee93e76959dd2969f0b1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt
@@ -32,6 +32,7 @@ import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper
 import org.matrix.android.sdk.internal.di.SessionDatabase
 import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask
 import org.matrix.android.sdk.internal.session.room.relation.threads.FetchThreadTimelineTask
+import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
 import org.matrix.android.sdk.internal.session.sync.handler.room.ReadReceiptHandler
 import org.matrix.android.sdk.internal.session.sync.handler.room.ThreadsAwarenessHandler
 import org.matrix.android.sdk.internal.util.time.Clock
@@ -53,7 +54,8 @@ internal class DefaultTimelineService @AssistedInject constructor(
         private val coroutineDispatchers: MatrixCoroutineDispatchers,
         private val timelineEventDataSource: TimelineEventDataSource,
         private val clock: Clock,
-        ) : TimelineService {
+        private val stateEventDataSource: StateEventDataSource,
+) : TimelineService {
 
     @AssistedFactory
     interface Factory {
@@ -78,7 +80,8 @@ internal class DefaultTimelineService @AssistedInject constructor(
                 getEventTask = contextOfEventTask,
                 threadsAwarenessHandler = threadsAwarenessHandler,
                 lightweightSettingsStorage = lightweightSettingsStorage,
-                clock = clock
+                clock = clock,
+                stateEventDataSource = stateEventDataSource,
         )
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveRoomStateListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveRoomStateListener.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b2692bf8051c7924a3c1c6573447c85b4bad48eb
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveRoomStateListener.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.internal.session.room.timeline
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.Observer
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+import org.matrix.android.sdk.api.query.QueryStringValue
+import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
+import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent
+import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
+
+/**
+ * Helper to observe and query the live room state.
+ */
+internal class LiveRoomStateListener(
+        roomId: String,
+        stateEventDataSource: StateEventDataSource,
+        private val mainDispatcher: CoroutineDispatcher,
+) {
+    private val roomStateObserver = Observer<List<Event>> { stateEvents ->
+        stateEvents.map { event ->
+            val memberContent = event.getFixedRoomMemberContent() ?: return@map
+            val stateKey = event.stateKey ?: return@map
+            liveRoomState[stateKey] = memberContent
+        }
+    }
+    private val stateEventsLiveData: LiveData<List<Event>> by lazy {
+        stateEventDataSource.getStateEventsLive(
+                roomId = roomId,
+                eventTypes = setOf(EventType.STATE_ROOM_MEMBER),
+                stateKey = QueryStringValue.NoCondition,
+        )
+    }
+
+    private val liveRoomState = mutableMapOf<String, RoomMemberContent>()
+
+    suspend fun start() = withContext(mainDispatcher) {
+        stateEventsLiveData.observeForever(roomStateObserver)
+    }
+
+    suspend fun stop() = withContext(mainDispatcher) {
+        if (stateEventsLiveData.hasActiveObservers()) {
+            stateEventsLiveData.removeObserver(roomStateObserver)
+        }
+    }
+
+    fun getLiveState(stateKey: String): RoomMemberContent? = liveRoomState[stateKey]
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt
index bcf202962c9399a88c8d51b14948137e555c5e31..4f65f85ce4ac31f4c03578068c5f1a3a013a5d9b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt
@@ -23,6 +23,7 @@ import io.realm.RealmConfiguration
 import io.realm.RealmResults
 import io.realm.kotlin.createObject
 import kotlinx.coroutines.CompletableDeferred
+import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
 import org.matrix.android.sdk.api.extensions.orFalse
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.MatrixError
@@ -41,6 +42,7 @@ import org.matrix.android.sdk.internal.database.query.findAllIncludingEvents
 import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfThread
 import org.matrix.android.sdk.internal.database.query.where
 import org.matrix.android.sdk.internal.session.room.relation.threads.FetchThreadTimelineTask
+import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
 import org.matrix.android.sdk.internal.session.sync.handler.room.ThreadsAwarenessHandler
 import org.matrix.android.sdk.internal.util.time.Clock
 import timber.log.Timber
@@ -100,7 +102,9 @@ internal class LoadTimelineStrategy constructor(
             val onEventsUpdated: (Boolean) -> Unit,
             val onEventsDeleted: () -> Unit,
             val onLimitedTimeline: () -> Unit,
-            val onNewTimelineEvents: (List<String>) -> Unit
+            val onNewTimelineEvents: (List<String>) -> Unit,
+            val stateEventDataSource: StateEventDataSource,
+            val matrixCoroutineDispatchers: MatrixCoroutineDispatchers,
     )
 
     private var getContextLatch: CompletableDeferred<Unit>? = null
@@ -165,7 +169,13 @@ internal class LoadTimelineStrategy constructor(
             onEventsUpdated = dependencies.onEventsUpdated
     )
 
-    fun onStart() {
+    private val liveRoomStateListener = LiveRoomStateListener(
+            roomId,
+            dependencies.stateEventDataSource,
+            dependencies.matrixCoroutineDispatchers.main
+    )
+
+    suspend fun onStart() {
         dependencies.eventDecryptor.start()
         dependencies.timelineInput.listeners.add(timelineInputListener)
         val realm = dependencies.realm.get()
@@ -174,9 +184,13 @@ internal class LoadTimelineStrategy constructor(
             it.addChangeListener(chunkEntityListener)
             timelineChunk = it.createTimelineChunk()
         }
+
+        if (dependencies.timelineSettings.useLiveSenderInfo) {
+            liveRoomStateListener.start()
+        }
     }
 
-    fun onStop() {
+    suspend fun onStop() {
         dependencies.eventDecryptor.destroy()
         dependencies.timelineInput.listeners.remove(timelineInputListener)
         chunkEntity?.removeChangeListener(chunkEntityListener)
@@ -188,6 +202,9 @@ internal class LoadTimelineStrategy constructor(
         if (mode is Mode.Thread) {
             clearThreadChunkEntity(dependencies.realm.get(), mode.rootThreadEventId)
         }
+        if (dependencies.timelineSettings.useLiveSenderInfo) {
+            liveRoomStateListener.stop()
+        }
     }
 
     suspend fun loadMore(count: Int, direction: Timeline.Direction, fetchOnServerIfNeeded: Boolean = true): LoadMoreResult {
@@ -222,7 +239,22 @@ internal class LoadTimelineStrategy constructor(
     }
 
     fun buildSnapshot(): List<TimelineEvent> {
-        return buildSendingEvents() + timelineChunk?.builtItems(includesNext = true, includesPrev = true).orEmpty()
+        val events = buildSendingEvents() + timelineChunk?.builtItems(includesNext = true, includesPrev = true).orEmpty()
+        return if (dependencies.timelineSettings.useLiveSenderInfo) {
+            events.map(this::applyLiveRoomState)
+        } else {
+            events
+        }
+    }
+
+    private fun applyLiveRoomState(event: TimelineEvent): TimelineEvent {
+        val updatedState = liveRoomStateListener.getLiveState(event.senderInfo.userId)
+        return if (updatedState != null) {
+            val updatedSenderInfo = event.senderInfo.copy(avatarUrl = updatedState.avatarUrl, displayName = updatedState.displayName)
+            event.copy(senderInfo = updatedSenderInfo)
+        } else {
+            event
+        }
     }
 
     private fun buildSendingEvents(): List<TimelineEvent> {
@@ -255,7 +287,7 @@ internal class LoadTimelineStrategy constructor(
 
     /**
      * Clear any existing thread chunk entity and create a new one, with the
-     * rootThreadEventId included
+     * rootThreadEventId included.
      */
     private fun recreateThreadChunkEntity(realm: Realm, rootThreadEventId: String) {
         realm.executeTransaction {
@@ -275,7 +307,7 @@ internal class LoadTimelineStrategy constructor(
     }
 
     /**
-     * Clear any existing thread chunk
+     * Clear any existing thread chunk.
      */
     private fun clearThreadChunkEntity(realm: Realm, rootThreadEventId: String) {
         realm.executeTransaction {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineChunk.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineChunk.kt
index 27f4245b22803d070865454db93e5478247bab35..6a5f9da8a64400255e9873968c870ec393b0095d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineChunk.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineChunk.kt
@@ -136,6 +136,7 @@ internal class TimelineChunk(
             val prevEvents = prevChunk?.builtItems(includesNext = false, includesPrev = true).orEmpty()
             deepBuiltItems.addAll(prevEvents)
         }
+
         return deepBuiltItems
     }
 
@@ -180,12 +181,14 @@ internal class TimelineChunk(
         val rootThreadEventId = timelineSettings.rootThreadEventId ?: return LoadMoreResult.FAILURE
         return if (direction == Timeline.Direction.BACKWARDS) {
             try {
-                fetchThreadTimelineTask.execute(FetchThreadTimelineTask.Params(
-                        roomId,
-                        rootThreadEventId,
-                        chunkEntity.prevToken,
-                        count
-                )).toLoadMoreResult()
+                fetchThreadTimelineTask.execute(
+                        FetchThreadTimelineTask.Params(
+                                roomId,
+                                rootThreadEventId,
+                                chunkEntity.prevToken,
+                                count
+                        )
+                ).toLoadMoreResult()
             } catch (failure: Throwable) {
                 Timber.e(failure, "Failed to fetch thread timeline events from the server")
                 LoadMoreResult.FAILURE
@@ -236,13 +239,15 @@ internal class TimelineChunk(
     }
 
     /**
-     * Simple log that displays the number and timeline of loaded events
+     * Simple log that displays the number and timeline of loaded events.
      */
     private fun logLoadedFromStorage(loadedFromStorage: LoadedFromStorage, direction: Timeline.Direction) {
-        Timber.v("[" +
-                "${if (timelineSettings.isThreadTimeline()) "ThreadTimeLine" else "Timeline"}] Has loaded " +
-                "${loadedFromStorage.numberOfEvents} items from storage in $direction " +
-                if (timelineSettings.isThreadTimeline() && loadedFromStorage.threadReachedEnd) "[Reached End]" else "")
+        Timber.v(
+                "[" +
+                        "${if (timelineSettings.isThreadTimeline()) "ThreadTimeLine" else "Timeline"}] Has loaded " +
+                        "${loadedFromStorage.numberOfEvents} items from storage in $direction " +
+                        if (timelineSettings.isThreadTimeline() && loadedFromStorage.threadReachedEnd) "[Reached End]" else ""
+        )
     }
 
     fun getBuiltEventIndex(eventId: String, searchInNext: Boolean, searchInPrev: Boolean): Int? {
@@ -361,7 +366,8 @@ internal class TimelineChunk(
                 }
         return LoadedFromStorage(
                 threadReachedEnd = threadReachedEnd(timelineEvents),
-                numberOfEvents = timelineEvents.size)
+                numberOfEvents = timelineEvents.size
+        )
     }
 
     /**
@@ -375,7 +381,7 @@ internal class TimelineChunk(
 
     /**
      * This function is responsible to fetch and store the root event of a thread event
-     * in order to be able to display the event to the user appropriately
+     * in order to be able to display the event to the user appropriately.
      */
     private suspend fun fetchRootThreadEventsIfNeeded(offsetResults: List<TimelineEventEntity>) {
         val eventEntityList = offsetResults
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt
index e5dd8aab304bd88ce008425b706e5eb9a494f666..96ceb6c6dca21ead391b0a860d527f79daee07df 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt
@@ -230,7 +230,8 @@ internal class TokenChunkEventPersistor @Inject constructor(
                         roomId = roomId,
                         eventEntity = eventEntity,
                         direction = direction,
-                        roomMemberContentsByUser = roomMemberContentsByUser)
+                        roomMemberContentsByUser = roomMemberContentsByUser
+                )
                 if (lightweightSettingsStorage.areThreadMessagesEnabled()) {
                     eventEntity.rootThreadEventId?.let {
                         // This is a thread event
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/UIEchoManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/UIEchoManager.kt
index 828e01955a0ab6cedc2d744f1ac249bf1f30b7ae..66bb04400b320b61294fc3b3f982a5d7b8e2b56a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/UIEchoManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/UIEchoManager.kt
@@ -44,7 +44,7 @@ internal class UIEchoManager(
     }
 
     /**
-     * Due to lag of DB updates, we keep some UI echo of some properties to update timeline faster
+     * Due to lag of DB updates, we keep some UI echo of some properties to update timeline faster.
      */
     private val inMemorySendingStates = Collections.synchronizedMap<String, SendState>(HashMap())
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/typing/DefaultTypingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/typing/DefaultTypingService.kt
index b76829e8937eda5fce2a22b5a446bab224855cbd..38ccd190204c68dcfa665c863e3574362cabb16d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/typing/DefaultTypingService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/typing/DefaultTypingService.kt
@@ -31,7 +31,7 @@ import timber.log.Timber
  * Rules:
  * - user is typing: notify the homeserver (true), at least once every 10s
  * - user stop typing: after 10s delay: notify the homeserver (false)
- * - user empty the text composer or quit the timeline screen: notify the homeserver (false)
+ * - user empty the text composer or quit the timeline screen: notify the homeserver (false).
  */
 internal class DefaultTypingService @AssistedInject constructor(
         @Assisted private val roomId: String,
@@ -53,7 +53,7 @@ internal class DefaultTypingService @AssistedInject constructor(
     private var lastRequestTimestamp: Long = 0
 
     /**
-     * Notify to the server that the user is typing and schedule the auto typing off
+     * Notify to the server that the user is typing and schedule the auto typing off.
      */
     override fun userIsTyping() {
         val now = SystemClock.elapsedRealtime()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt
index 8033b0654da4a2b96f4beb40acec4dfc0cb04a3b..12ca36fa6bb52c31f9ed620cd20145490e050b9f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt
@@ -32,15 +32,17 @@ internal class DefaultSearchService @Inject constructor(
                                 beforeLimit: Int,
                                 afterLimit: Int,
                                 includeProfile: Boolean): SearchResult {
-        return searchTask.execute(SearchTask.Params(
-                searchTerm = searchTerm,
-                roomId = roomId,
-                nextBatch = nextBatch,
-                orderByRecent = orderByRecent,
-                limit = limit,
-                beforeLimit = beforeLimit,
-                afterLimit = afterLimit,
-                includeProfile = includeProfile
-        ))
+        return searchTask.execute(
+                SearchTask.Params(
+                        searchTerm = searchTerm,
+                        roomId = roomId,
+                        nextBatch = nextBatch,
+                        orderByRecent = orderByRecent,
+                        limit = limit,
+                        beforeLimit = beforeLimit,
+                        afterLimit = afterLimit,
+                        includeProfile = includeProfile
+                )
+        )
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt
index fcaf3b60a761a1f156d91fb5c4d2dc06eeaa3432..f785ed42663919975915fe22c3ec88299b7df0f8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchTask.kt
@@ -112,7 +112,7 @@ internal class DefaultSearchTask @Inject constructor(
     }
 
     /**
-     * Find local events if exists in order to enhance the result with thread summary
+     * Find local events if exists in order to enhance the result with thread summary.
      */
     private fun findRootThreadEventsFromDB(searchResponseItemList: List<SearchResponseItem>?): List<TimelineEventEntity>? {
         return realmSessionProvider.withRealm { realm ->
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt
index 60643818089d28477bdcf601c86d617525dc9bc9..e78c170a3277d5c69182550253ece049ca857d9e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/request/SearchRequestRoomEvents.kt
@@ -55,7 +55,7 @@ internal data class SearchRequestRoomEvents(
          * Requests the server return the current state for each room returned.
          */
         @Json(name = "include_state")
-        val include_state: Boolean? = null
+        val includeState: Boolean? = null
 
         /**
          * Requests that the server partitions the result set based on the provided list of keys.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt
index 17dc90fdb0e09d32b206f3b2bb886143b9e930d8..07a5cbe5a0249d26f6f26b2c4b07d37dac73e57e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt
@@ -129,7 +129,7 @@ internal class SecretStoringUtils @Inject constructor(
     }
 
     /**
-     * Decrypt a secret that was encrypted by #securelyStoreString()
+     * Decrypt a secret that was encrypted by #securelyStoreString().
      */
     @SuppressLint("NewApi")
     @Throws(Exception::class)
@@ -169,8 +169,10 @@ internal class SecretStoringUtils @Inject constructor(
         if (secretKeyEntry == null) {
             // we generate it
             val generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
-            val keyGenSpec = KeyGenParameterSpec.Builder(alias,
-                    KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
+            val keyGenSpec = KeyGenParameterSpec.Builder(
+                    alias,
+                    KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
+            )
                     .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                     .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                     .setKeySize(128)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/JoinSpaceTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/JoinSpaceTask.kt
index 7eeaed4ff62095ec8d7310ffc9c3b2d750672192..a0925cabcce47d3a5ddea3f7c7e67f866b6a5fb5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/JoinSpaceTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/JoinSpaceTask.kt
@@ -49,11 +49,13 @@ internal class DefaultJoinSpaceTask @Inject constructor(
     override suspend fun execute(params: JoinSpaceTask.Params): JoinSpaceResult {
         Timber.v("## Space: > Joining root space ${params.roomIdOrAlias} ...")
         try {
-            joinRoomTask.execute(JoinRoomTask.Params(
-                    params.roomIdOrAlias,
-                    params.reason,
-                    params.viaServers
-            ))
+            joinRoomTask.execute(
+                    JoinRoomTask.Params(
+                            params.roomIdOrAlias,
+                            params.reason,
+                            params.viaServers
+                    )
+            )
         } catch (failure: Throwable) {
             return JoinSpaceResult.Fail(failure)
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/SpaceApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/SpaceApi.kt
index fda9b4b5bc6db6418bb8e54b5d7242cd3452d4bc..d8daa55e150e2bcd64e8be5548de35a0396cabd6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/SpaceApi.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/SpaceApi.kt
@@ -40,7 +40,7 @@ internal interface SpaceApi {
             @Query("from") from: String?): SpacesResponse
 
     /**
-     * Unstable version of [getSpaceHierarchy]
+     * Unstable version of [getSpaceHierarchy].
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "org.matrix.msc2946/rooms/{roomId}/hierarchy")
     suspend fun getSpaceHierarchyUnstable(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/SpaceChildSummaryResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/SpaceChildSummaryResponse.kt
index b6a9c73d36596323af4f8855b7ac259e4fbad87c..e3f8977ac59bd5dd6ac6547310ee13215fee7b44 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/SpaceChildSummaryResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/SpaceChildSummaryResponse.kt
@@ -97,7 +97,7 @@ internal data class SpaceChildSummaryResponse(
         val avatarUrl: String? = null,
 
         /**
-         * Undocumented item
+         * Undocumented item.
          */
         @Json(name = "m.federate")
         val isFederated: Boolean = false
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/InitialSyncStatusRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/InitialSyncStatusRepository.kt
index 8e0c3422b933d81806fdfa9126a07f30b19fa6fa..e90df3d39dcd79c20ed084bb3da052aa9c4b03d7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/InitialSyncStatusRepository.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/InitialSyncStatusRepository.kt
@@ -45,7 +45,7 @@ internal interface InitialSyncStatusRepository {
 }
 
 /**
- * This class handle the current status of an initial sync and persist it on the disk, to be robust against crash
+ * This class handle the current status of an initial sync and persist it on the disk, to be robust against crash.
  */
 internal class FileInitialSyncStatusRepository(
         directory: File,
@@ -95,7 +95,7 @@ internal class FileInitialSyncStatusRepository(
     }
 
     /**
-     * File -> Cache
+     * File -> Cache.
      */
     private fun readFile() {
         cache = file
@@ -104,7 +104,7 @@ internal class FileInitialSyncStatusRepository(
     }
 
     /**
-     * Cache -> File
+     * Cache -> File.
      */
     private fun writeFile() {
         file.delete()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncEphemeralTemporaryStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncEphemeralTemporaryStore.kt
index ef9f468c8645394af7b2e3dd50cc68cd60e0bb22..0e48cddc2d427bbcac6e8ea3eb6fe3f3b666c863 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncEphemeralTemporaryStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncEphemeralTemporaryStore.kt
@@ -48,7 +48,7 @@ internal class RoomSyncEphemeralTemporaryStoreFile @Inject constructor(
     private val roomSyncEphemeralAdapter = moshi.adapter(RoomSyncEphemeral::class.java)
 
     /**
-     * Write RoomSyncEphemeral to a file
+     * Write RoomSyncEphemeral to a file.
      */
     override fun write(roomId: String, roomSyncEphemeralJson: String) {
         Timber.w("INIT_SYNC Store ephemeral events for room $roomId")
@@ -56,7 +56,7 @@ internal class RoomSyncEphemeralTemporaryStoreFile @Inject constructor(
     }
 
     /**
-     * Read RoomSyncEphemeral from a file, or null if there is no file to read
+     * Read RoomSyncEphemeral from a file, or null if there is no file to read.
      */
     override fun read(roomId: String): RoomSyncEphemeral? {
         return getFile(roomId)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncAPI.kt
index 73ec0aa7ef1a5891eb7d21f3f6515442bcb1b4f8..6c8a71f35ecd02a6875d2d70fc0e9f5561eb88e6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncAPI.kt
@@ -28,7 +28,7 @@ import retrofit2.http.Streaming
 
 internal interface SyncAPI {
     /**
-     * Set all the timeouts to 1 minute by default
+     * Set all the timeouts to 1 minute by default.
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "sync")
     suspend fun sync(@QueryMap params: Map<String, String>,
@@ -38,7 +38,7 @@ internal interface SyncAPI {
     ): SyncResponse
 
     /**
-     * Set all the timeouts to 1 minute by default
+     * Set all the timeouts to 1 minute by default.
      */
     @Streaming
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "sync")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncPresence.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncPresence.kt
index 42cd972e0cf93bda572d5ed58d801feba5bfcc20..ce41a4568cdf190c16a47da9739366a8c61a444b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncPresence.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncPresence.kt
@@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.session.presence.model.PresenceEnum
 internal enum class SyncPresence(val value: String) {
     Offline("offline"),
     Online("online"),
+    Busy("busy"),
     Unavailable("unavailable");
 
     companion object {
@@ -36,6 +37,7 @@ internal enum class SyncPresence(val value: String) {
             return when (presenceEnum) {
                 PresenceEnum.ONLINE      -> Online
                 PresenceEnum.OFFLINE     -> Offline
+                PresenceEnum.BUSY        -> Busy
                 PresenceEnum.UNAVAILABLE -> Unavailable
             }
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt
index 429f4985334d77e4f5fefedb72b4a38ecbf32002..dd9576216649bac3d7129c941e64646b05b4d12c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt
@@ -60,7 +60,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
     }
 
     /**
-     * Decrypt an encrypted event
+     * Decrypt an encrypted event.
      *
      * @param event      the event to decrypt
      * @param timelineId the timeline identifier
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/PresenceSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/PresenceSyncHandler.kt
index 6a7af1dda4a86fa3b005cff30a96cc0fe8c3fabb..0d4c06339b502c295f960a30bb5963d608750f7e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/PresenceSyncHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/PresenceSyncHandler.kt
@@ -52,7 +52,7 @@ internal class PresenceSyncHandler @Inject constructor(private val matrixConfigu
     }
 
     /**
-     * Store user presence to DB and update Direct Rooms and Room Member Summaries accordingly
+     * Store user presence to DB and update Direct Rooms and Room Member Summaries accordingly.
      */
     private fun storePresenceToDB(realm: Realm, userPresenceEntity: UserPresenceEntity) =
             realm.copyToRealmOrUpdate(userPresenceEntity)?.apply {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt
index 5437a015fdf25d17dfb7bec7796c7c1cbc423d7b..c5d14afac0096ac9afb401b81f2a7e8ca172ead0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt
@@ -213,7 +213,7 @@ internal class RoomSyncHandler @Inject constructor(
         val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
 
         val ephemeralResult = (roomSync.ephemeral as? LazyRoomSyncEphemeral.Parsed)
-                ?._roomSyncEphemeral
+                ?.roomSyncEphemeral
                 ?.events
                 ?.takeIf { it.isNotEmpty() }
                 ?.let { handleEphemeral(realm, roomId, it, insertType == EventInsertType.INITIAL_SYNC, aggregator) }
@@ -382,7 +382,10 @@ internal class RoomSyncHandler @Inject constructor(
         val roomMemberContentsByUser = HashMap<String, RoomMemberContent?>()
 
         val optimizedThreadSummaryMap = hashMapOf<String, EventEntity>()
-        for (event in eventList) {
+        for (rawEvent in eventList) {
+            // It's annoying roomId is not there, but lot of code rely on it.
+            // And had to do it now as copy would delete all decryption results..
+            val event = rawEvent.copy(roomId = roomId)
             if (event.eventId == null || event.senderId == null || event.type == null) {
                 continue
             }
@@ -454,7 +457,7 @@ internal class RoomSyncHandler @Inject constructor(
                 }
             }
             // Give info to crypto module
-            cryptoService.onLiveEvent(roomEntity.roomId, event)
+            cryptoService.onLiveEvent(roomEntity.roomId, event, isInitialSync)
 
             // Try to remove local echo
             event.unsignedData?.transactionId?.also {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ThreadsAwarenessHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ThreadsAwarenessHandler.kt
index efc8e39a18d8873fab3926a35ea9ef0633aba034..03e076c217726f29c2d0ebffb36b04b55a9c3349 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ThreadsAwarenessHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ThreadsAwarenessHandler.kt
@@ -73,7 +73,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
     private val cacheEventRootId = hashSetOf<String>()
 
     /**
-     * Fetch root thread events if they are missing from the local storage
+     * Fetch root thread events if they are missing from the local storage.
      * @param syncResponse the sync response
      */
     suspend fun fetchRootThreadEventsIfNeeded(syncResponse: SyncResponse) {
@@ -92,7 +92,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
     }
 
     /**
-     * Fetch root thread events if they are missing from the local storage
+     * Fetch root thread events if they are missing from the local storage.
      * @param eventList a list with the events to examine
      */
     suspend fun fetchRootThreadEventsIfNeeded(eventList: List<Event>) {
@@ -115,7 +115,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
     }
 
     /**
-     * Fetch multiple unique events using the fetchEvent function
+     * Fetch multiple unique events using the fetchEvent function.
      */
     private suspend fun fetchThreadsEvents(threadsToFetch: Map<String, String>) {
         val eventEntityList = threadsToFetch.mapNotNull { (eventId, roomId) ->
@@ -153,7 +153,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
     }
 
     /**
-     * Handle events mainly coming from the RoomSyncHandler
+     * Handle events mainly coming from the RoomSyncHandler.
      * @return The content to inject in the roomSyncHandler live events
      */
     fun makeEventThreadAware(realm: Realm,
@@ -186,7 +186,8 @@ internal class ThreadsAwarenessHandler @Inject constructor(
                     eventBody = eventBody,
                     eventToInject = eventToInject,
                     eventToInjectBody = eventToInjectBody,
-                    threadRelation = threadRelation) ?: return null
+                    threadRelation = threadRelation
+            ) ?: return null
 
             // update the event
             contentForNonEncrypted = updateEventEntity(event, eventEntity, eventPayload, messageTextContent)
@@ -225,9 +226,9 @@ internal class ThreadsAwarenessHandler @Inject constructor(
     }
 
     /**
-     * This function is responsible to check if there is any event that relates to our current event
+     * This function is responsible to check if there is any event that relates to our current event.
      * This is useful when we receive an event that relates to a missing parent, so when later we receive the parent
-     * we can update the child as well
+     * we can update the child as well.
      * @param event the current event that we examine
      * @param eventBody the current body of the event
      * @param isFromCache determines whether or not we already know this is root thread event
@@ -253,7 +254,8 @@ internal class ThreadsAwarenessHandler @Inject constructor(
                     eventBody = newEventBody,
                     eventToInject = event,
                     eventToInjectBody = eventBody,
-                    threadRelation = threadRelation) ?: return null
+                    threadRelation = threadRelation
+            ) ?: return null
 
             return updateEventEntity(newEventFound, eventEntityFound, newEventPayload, messageTextContent)
         }
@@ -261,7 +263,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
     }
 
     /**
-     * Actual update the eventEntity with the new payload
+     * Actual update the eventEntity with the new payload.
      * @return the content to inject when this is executed by RoomSyncHandler
      */
     private fun updateEventEntity(event: Event,
@@ -289,7 +291,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
     }
 
     /**
-     * Injecting $eventToInject decrypted content as a reply to $event
+     * Injecting $eventToInject decrypted content as a reply to $event.
      * @param eventToInject the event that will inject
      * @param eventBody the actual event body
      * @return The final content with the injected event
@@ -309,7 +311,8 @@ internal class ThreadsAwarenessHandler @Inject constructor(
                 userLink,
                 eventIdToInjectSenderId,
                 eventToInjectBody,
-                eventBody)
+                eventBody
+        )
 
         return MessageTextContent(
                 relatesTo = threadRelation,
@@ -321,7 +324,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
     }
 
     /**
-     * Integrate fallback Quote reply
+     * Integrate fallback Quote reply.
      */
     private fun injectFallbackIndicator(event: Event,
                                         eventBody: String,
@@ -330,7 +333,8 @@ internal class ThreadsAwarenessHandler @Inject constructor(
                                         threadRelation: RelationDefaultContent?): String? {
         val replyFormatted = LocalEchoEventFactory.QUOTE_PATTERN.format(
                 "In reply to a thread",
-                eventBody)
+                eventBody
+        )
 
         val messageTextContent = MessageTextContent(
                 relatesTo = threadRelation,
@@ -360,7 +364,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
 
     /**
      * Try to get the event form the local DB, if the event does not exist null
-     * will be returned
+     * will be returned.
      */
     private fun getEventFromDB(realm: Realm, eventId: String): Event? {
         val eventEntity = EventEntity.where(realm, eventId = eventId).findFirst() ?: return null
@@ -368,14 +372,14 @@ internal class ThreadsAwarenessHandler @Inject constructor(
     }
 
     /**
-     * Returns True if the event is a thread
+     * Returns True if the event is a thread.
      * @param event
      */
     private fun isThreadEvent(event: Event): Boolean =
             event.content.toModel<MessageRelationContent>()?.relatesTo?.type == RelationType.THREAD
 
     /**
-     * Returns the root thread eventId or null otherwise
+     * Returns the root thread eventId or null otherwise.
      * @param event
      */
     private fun getRootThreadEventId(event: Event): String? =
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt
index f183c4cb28cd5c67f139270255114c817925e6f3..bbb18b664c6bf43a72b9024c7f593a243800cad4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt
@@ -38,8 +38,8 @@ private const val DEFAULT_LONG_POOL_TIMEOUT_SECONDS = 6L
 private const val DEFAULT_DELAY_MILLIS = 30_000L
 
 /**
- * Possible previous worker: None
- * Possible next worker    : None
+ * Possible previous worker: None.
+ * Possible next worker    : None.
  */
 internal class SyncWorker(context: Context, workerParameters: WorkerParameters, sessionManager: SessionManager) :
         SessionSafeCoroutineWorker<SyncWorker.Params>(context, workerParameters, sessionManager, Params::class.java) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/DeviceInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/DeviceInfo.kt
index fdb9916190bffb60a98db00b3cc8a4b6ac4c5d10..7f6759906f2a4284f4232c6588ca6598064785cd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/DeviceInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/DeviceInfo.kt
@@ -19,24 +19,24 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * This class describes the device information
+ * This class describes the device information.
  */
 @JsonClass(generateAdapter = true)
 internal data class DeviceInfo(
         /**
-         * The owner user id
+         * The owner user id.
          */
         @Json(name = "user_id")
         val userId: String? = null,
 
         /**
-         * The device id
+         * The device id.
          */
         @Json(name = "device_id")
         val deviceId: String? = null,
 
         /**
-         * The device display name
+         * The device display name.
          */
         @Json(name = "display_name")
         val displayName: String? = null,
@@ -48,7 +48,7 @@ internal data class DeviceInfo(
         val lastSeenTs: Long = 0,
 
         /**
-         * The last ip address
+         * The last ip address.
          */
         @Json(name = "last_seen_ip")
         val lastSeenIp: String? = null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/DevicesListResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/DevicesListResponse.kt
index 3dc71a355dbd0dd07f5b33bf40b21b588deb1ee7..acef22a5429323dcaf84eebb2dac9097cfcee510 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/DevicesListResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/DevicesListResponse.kt
@@ -17,9 +17,6 @@ package org.matrix.android.sdk.internal.session.sync.model
 
 import com.squareup.moshi.JsonClass
 
-/**
- * This class describes the
- */
 @JsonClass(generateAdapter = true)
 internal data class DevicesListResponse(
         val devices: List<DeviceInfo>? = null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/accountdata/DirectMessagesContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/accountdata/DirectMessagesContent.kt
index 7c73f1fed0762f70f5b750553c9e9c8485d34f8e..2e45b2ad985ba52de67934d087d70bd4fb291e95 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/accountdata/DirectMessagesContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/accountdata/DirectMessagesContent.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.internal.session.sync.model.accountdata
 
 /**
- * Keys are userIds, values are list of roomIds
+ * Keys are userIds, values are list of roomIds.
  */
 internal typealias DirectMessagesContent = Map<String, List<String>>
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/AcceptTermsBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/AcceptTermsBody.kt
index ee23c9e6bc4c3b39c0c525e2ac051c857abba0b1..bf954b0aee7fb6ee7cca927b34a99d7160850d90 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/AcceptTermsBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/AcceptTermsBody.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * This class represent a list of urls of terms the user wants to accept
+ * This class represent a list of urls of terms the user wants to accept.
  */
 @JsonClass(generateAdapter = true)
 internal data class AcceptTermsBody(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt
index 5f62f40ab3f45ace08f439fe87966abd30d723a0..9876643bed1a6c8ca3ff0c3ced398ef91183d11b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt
@@ -61,7 +61,7 @@ internal class DefaultTermsService @Inject constructor(
     }
 
     /**
-     * We use a trick here to get the homeserver T&C, we use the register API
+     * We use a trick here to get the homeserver T&C, we use the register API.
      */
     override suspend fun getHomeserverTerms(baseUrl: String): TermsResponse {
         return try {
@@ -108,9 +108,11 @@ internal class DefaultTermsService @Inject constructor(
 
         val newList = listOfAcceptedTerms.toMutableSet().apply { addAll(agreedUrls) }.toList()
 
-        updateUserAccountDataTask.execute(UpdateUserAccountDataTask.AcceptedTermsParams(
-                acceptedTermsContent = AcceptedTermsContent(newList)
-        ))
+        updateUserAccountDataTask.execute(
+                UpdateUserAccountDataTask.AcceptedTermsParams(
+                        acceptedTermsContent = AcceptedTermsContent(newList)
+                )
+        )
     }
 
     private suspend fun getToken(url: String): String {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt
index 1f117de67e529e7303d66cc83becba4da03be002..f6f57bf0ef0919b0c4fc4dfbc720d9186c6ccf80 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt
@@ -28,13 +28,13 @@ import retrofit2.http.Url
 
 internal interface TermsAPI {
     /**
-     * This request does not require authentication
+     * This request does not require authentication.
      */
     @GET
     suspend fun getTerms(@Url url: String): TermsResponse
 
     /**
-     * This request requires authentication
+     * This request requires authentication.
      */
     @POST
     suspend fun agreeToTerms(@Url url: String,
@@ -43,7 +43,7 @@ internal interface TermsAPI {
 
     /**
      * API to retrieve the terms for a homeserver. The API /terms does not exist yet, so retrieve the terms from the login flow.
-     * We do not care about the result (Credentials)
+     * We do not care about the result (Credentials).
      */
     @POST
     suspend fun register(@Url url: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/typing/DefaultTypingUsersTracker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/typing/DefaultTypingUsersTracker.kt
index c5c3fc4b59525920c2679e001b688146de6f4e66..ac4a886aa3567ac7d83ed627b5d6fe423a920ae5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/typing/DefaultTypingUsersTracker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/typing/DefaultTypingUsersTracker.kt
@@ -27,7 +27,7 @@ internal class DefaultTypingUsersTracker @Inject constructor() : TypingUsersTrac
     private val typingUsers = mutableMapOf<String, List<SenderInfo>>()
 
     /**
-     * Set all currently typing users for a room (excluding yourself)
+     * Set all currently typing users for a room (excluding yourself).
      */
     fun setTypingUsersFromRoom(roomId: String, senderInfoList: List<SenderInfo>) {
         val hasNewValue = typingUsers[roomId] != senderInfoList
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataContent.kt
index 5f9f0777d8b5915c473772907022ab63f8aa0ca2..c3daa2a0e9820c54353c66bc3e1a874d5c638fc8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataContent.kt
@@ -17,6 +17,6 @@
 package org.matrix.android.sdk.internal.session.user.accountdata
 
 /**
- * Tag class to identify every account data content
+ * Tag class to identify every account data content.
  */
 internal interface AccountDataContent
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 59c4dd671eb25e14ee771a7ca3ffa928773a51a0..df9dcfb903ec533efddbd1b77f93e73e043c7d4b 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
@@ -68,7 +68,7 @@ internal class DefaultSessionAccountDataService @Inject constructor(
         val params = UpdateUserAccountDataTask.AnyParams(type = type, any = content)
         awaitCallback<Unit> { callback ->
             updateUserAccountDataTask.configureWith(params) {
-                this.retryCount = 5 // TODO: Need to refactor retrying out into a helper method.
+                this.retryCount = 5 // TODO Need to refactor retrying out into a helper method.
                 this.callback = callback
             }
                     .executeBy(taskExecutor)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/SaveBreadcrumbsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/SaveBreadcrumbsTask.kt
index 22af56a169609146b2223aca256dd0feda8be799..148f9d657df46b26884da1fe12707b08b72cd028 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/SaveBreadcrumbsTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/SaveBreadcrumbsTask.kt
@@ -29,7 +29,7 @@ import org.matrix.android.sdk.internal.util.awaitTransaction
 import javax.inject.Inject
 
 /**
- * Save the Breadcrumbs roomId list in DB, either from the sync, or updated locally
+ * Save the Breadcrumbs roomId list in DB, either from the sync, or updated locally.
  */
 internal interface SaveBreadcrumbsTask : Task<SaveBreadcrumbsTask.Params, Unit> {
     data class Params(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateBreadcrumbsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateBreadcrumbsTask.kt
index 874c2741de807b2d1922a23d8d2aa90db6cf5ba3..c4ea029cbb0f2022b4c47016926b64b2e8ada37a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateBreadcrumbsTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateBreadcrumbsTask.kt
@@ -60,8 +60,10 @@ internal class DefaultUpdateBreadcrumbsTask @Inject constructor(
 
         // FIXME It can remove the previous breadcrumbs, if not synced yet
         // And update account data
-        updateUserAccountDataTask.execute(UpdateUserAccountDataTask.BreadcrumbsParams(
-                breadcrumbsContent = BreadcrumbsContent(newBreadcrumbs)
-        ))
+        updateUserAccountDataTask.execute(
+                UpdateUserAccountDataTask.BreadcrumbsParams(
+                        breadcrumbsContent = BreadcrumbsContent(newBreadcrumbs)
+                )
+        )
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/model/SearchUsersParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/model/SearchUsersParams.kt
index 46285965b413f9f4441c51abf8f44463c3c366bd..29d957f2bfbe856f7566a5faacdb5f273afd2d30 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/model/SearchUsersParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/model/SearchUsersParams.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing an user search parameters
+ * Class representing an user search parameters.
  */
 @JsonClass(generateAdapter = true)
 internal data class SearchUsersParams(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/model/SearchUsersResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/model/SearchUsersResponse.kt
index e2a93abde018c563361c2ff2ea7773604cc15f1b..058bf09da698aa2110f2872bf989edceea4ca4e7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/model/SearchUsersResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/model/SearchUsersResponse.kt
@@ -20,7 +20,7 @@ import com.squareup.moshi.Json
 import com.squareup.moshi.JsonClass
 
 /**
- * Class representing an users search response
+ * Class representing an users search response.
  */
 @JsonClass(generateAdapter = true)
 internal data class SearchUsersResponse(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetPostAPIMediator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetPostAPIMediator.kt
index 9f42688f7d63ebf732f6328387711dba6c9af310..1da682791618ff56e64b84ec3aafe41878202306 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetPostAPIMediator.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetPostAPIMediator.kt
@@ -93,7 +93,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
      */
 
     /**
-     * Send a boolean response
+     * Send a boolean response.
      *
      * @param response  the response
      * @param eventData the modular data
@@ -104,7 +104,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
     }
 
     /**
-     * Send an integer response
+     * Send an integer response.
      *
      * @param response  the response
      * @param eventData the modular data
@@ -114,7 +114,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
     }
 
     /**
-     * Send an object response
+     * Send an object response.
      *
      * @param response  the response
      * @param eventData the modular data
@@ -133,7 +133,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
     }
 
     /**
-     * Send success
+     * Send success.
      *
      * @param eventData the modular data
      */
@@ -143,7 +143,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
     }
 
     /**
-     * Send an error
+     * Send an error.
      *
      * @param message   the error message
      * @param eventData the modular data
@@ -151,7 +151,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
     override fun sendError(message: String, eventData: JsonDict) {
         Timber.e("## sendError() : eventData $eventData failed $message")
 
-        // TODO: JS has an additional optional parameter: nestedError
+        // TODO JS has an additional optional parameter: nestedError
         val params = HashMap<String, Map<String, String>>()
         val subMap = HashMap<String, String>()
         subMap["message"] = message
@@ -160,7 +160,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
     }
 
     /**
-     * Send the response to the javascript
+     * Send the response to the javascript.
      *
      * @param jsString  the response data
      * @param eventData the modular data
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPI.kt
index bfc243c213a866b942911fd4d48efd6d48bd67d6..b871a317c88c5217afda2c97f385e2918b943d15 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPI.kt
@@ -24,7 +24,7 @@ import retrofit2.http.Query
 internal interface WidgetsAPI {
 
     /**
-     * register to the server
+     * Register to the server.
      *
      * @param body the body content (Ref: https://github.com/matrix-org/matrix-doc/pull/1961)
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Base64.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Base64.kt
index aae8bf19671e66cfd4744278896da24a4019a109..ea7d75a42cef62ef786bb0e1158c8ba20b82c004 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Base64.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Base64.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.internal.util
 
 /**
- * Base64 URL conversion methods
+ * Base64 URL conversion methods.
  */
 
 internal fun base64UrlToBase64(base64Url: String): String {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/MathUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/BestChunkSize.kt
similarity index 100%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/MathUtils.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/BestChunkSize.kt
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CancelableCoroutine.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CancelableCoroutine.kt
index f398ee25d8b1831d2e7cdeb1cbd226b0e206e607..74b54943cd9e99573b80f160d441ddc3b8b1f050 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CancelableCoroutine.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CancelableCoroutine.kt
@@ -24,7 +24,7 @@ internal fun Job.toCancelable(): Cancelable {
 }
 
 /**
- * Private, use the extension above
+ * Private, use the extension above.
  */
 private class CancelableCoroutine(private val job: Job) : Cancelable {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FailureExt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FailureExt.kt
index 8c78feeac3d883d6d2ab668946a4254e1c86cc49..0d6555570792c6c7568559f1c44a89fad6e1e687 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FailureExt.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FailureExt.kt
@@ -22,7 +22,7 @@ import org.matrix.android.sdk.api.failure.MatrixError
 import org.matrix.android.sdk.internal.di.MoshiProvider
 
 /**
- * Try to extract and serialize a MatrixError, or default to localizedMessage
+ * Try to extract and serialize a MatrixError, or default to localizedMessage.
  */
 internal fun Throwable.toMatrixErrorStr(): String {
     return (this as? Failure.ServerError)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt
index 3fcf35c127cec270d04dc42c73e592cbf7543d04..1bd704a9e84a4ea2f23c9653d3bebc6cdcdcb82a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt
@@ -21,7 +21,7 @@ import java.io.File
 import java.io.InputStream
 
 /**
- * Save an input stream to a file with Okio
+ * Save an input stream to a file with Okio.
  */
 @WorkerThread
 internal fun writeToFile(inputStream: InputStream, outputFile: File) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/JsonCanonicalizer.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/JsonCanonicalizer.kt
index 5994cbcf93fca7ac35a32f0609438f81dbc9de9c..94aa238789fd9dbc8e28bb598a66e2fa744ab3c0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/JsonCanonicalizer.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/JsonCanonicalizer.kt
@@ -51,7 +51,7 @@ internal object JsonCanonicalizer {
     }
 
     /**
-     * Canonicalize a JSON element
+     * Canonicalize a JSON element.
      *
      * @param src the src
      * @return the canonicalize element
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/SecretKeyAndVersion.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/SecretKeyAndVersion.kt
index 40aead5d637f8d6d75462cc781ef67b72ff04a86..79a15546105f4549c86cf395ed507fecdd69a854 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/SecretKeyAndVersion.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/SecretKeyAndVersion.kt
@@ -19,14 +19,15 @@ package org.matrix.android.sdk.internal.util
 import javax.crypto.SecretKey
 
 /**
- * Tuple which contains the secret key and the version of Android when the key has been generated
+ * Tuple which contains the secret key and the version of Android when the key has been generated.
  */
 internal data class SecretKeyAndVersion(
         /**
-         * the key
+         * the key.
          */
         val secretKey: SecretKey,
         /**
-         * The android version when the key has been generated
+         * The android version when the key has been generated.
          */
-        val androidVersionWhenTheKeyHasBeenGenerated: Int)
+        val androidVersionWhenTheKeyHasBeenGenerated: Int
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt
index 8a6ec189863849f588054103a06e00a117a44376..d9fd312a6fc1d4a9d2635eff929a219cd88c6a75 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt
@@ -20,7 +20,7 @@ import timber.log.Timber
 import java.util.Locale
 
 /**
- * Convert a string to an UTF8 String
+ * Convert a string to an UTF8 String.
  *
  * @param s the string to convert
  * @return the utf-8 string
@@ -36,7 +36,7 @@ internal fun convertToUTF8(s: String): String {
 }
 
 /**
- * Convert a string from an UTF8 String
+ * Convert a string from an UTF8 String.
  *
  * @param s the string to convert
  * @return the utf-16 string
@@ -76,7 +76,7 @@ internal fun String.caseInsensitiveFind(subString: String): Boolean {
 internal val spaceChars = "[\u00A0\u2000-\u200B\u2800\u3000]".toRegex()
 
 /**
- * Strip all the UTF-8 chars which are actually spaces
+ * Strip all the UTF-8 chars which are actually spaces.
  */
 internal fun String.replaceSpaceChars(replacement: String = "") = replace(spaceChars, replacement)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/UrlUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/UrlUtils.kt
index d13753b5ee582e740f22f729c9345d7f203911cd..fbbec1a100985df2227a000d373104c27bae3f35 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/UrlUtils.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/UrlUtils.kt
@@ -39,7 +39,7 @@ internal fun String.ensureProtocol(): String {
 }
 
 /**
- * Ensure string has trailing /
+ * Ensure string ends with "/", if not empty.
  */
 internal fun String.ensureTrailingSlash(): String {
     return when {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/system/BuildVersionSdkIntProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/system/BuildVersionSdkIntProvider.kt
index b660796ad82d483d993e815171f418bd60d27b0c..515656049a0fe1af25056af5f64aae720a0fd122 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/system/BuildVersionSdkIntProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/system/BuildVersionSdkIntProvider.kt
@@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.util.system
 
 internal interface BuildVersionSdkIntProvider {
     /**
-     * Return the current version of the Android SDK
+     * Return the current version of the Android SDK.
      */
     fun get(): Int
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt
index 82ff9a321fcc068f35746bd98fc2a9b63099dcc5..0d4a5ac28f25400a56b3c1a39ef498cca8cb6c98 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt
@@ -39,16 +39,16 @@ import javax.net.ssl.HttpsURLConnection
 internal interface GetWellknownTask : Task<GetWellknownTask.Params, WellknownResult> {
     data class Params(
             /**
-             * domain, for instance "matrix.org"
+             * domain, for instance "matrix.org".
              * the URL will be https://{domain}/.well-known/matrix/client
              */
             val domain: String,
-            val homeServerConnectionConfig: HomeServerConnectionConfig?
+            val homeServerConnectionConfig: HomeServerConnectionConfig
     )
 }
 
 /**
- * Inspired from AutoDiscovery class from legacy Matrix Android SDK
+ * Inspired from AutoDiscovery class from legacy Matrix Android SDK.
  */
 internal class DefaultGetWellknownTask @Inject constructor(
         @Unauthenticated
@@ -61,19 +61,15 @@ internal class DefaultGetWellknownTask @Inject constructor(
         return findClientConfig(params.domain, client)
     }
 
-    private fun buildClient(homeServerConnectionConfig: HomeServerConnectionConfig?): OkHttpClient {
-        return if (homeServerConnectionConfig != null) {
-            okHttpClient.get()
-                    .newBuilder()
-                    .addSocketFactory(homeServerConnectionConfig)
-                    .build()
-        } else {
-            okHttpClient.get()
-        }
+    private fun buildClient(homeServerConnectionConfig: HomeServerConnectionConfig): OkHttpClient {
+        return okHttpClient.get()
+                .newBuilder()
+                .addSocketFactory(homeServerConnectionConfig)
+                .build()
     }
 
     /**
-     * Find client config
+     * Find client config.
      *
      * - Do the .well-known request
      * - validate homeserver url and identity server url if provide in .well-known result
@@ -130,7 +126,7 @@ internal class DefaultGetWellknownTask @Inject constructor(
     }
 
     /**
-     * Return true if homeserver is valid, and (if applicable) if identity server is pingable
+     * Return true if homeserver is valid, and (if applicable) if identity server is pingable.
      */
     private suspend fun validateHomeServer(homeServerBaseUrl: String, wellKnown: WellKnown, client: OkHttpClient): WellknownResult {
         val capabilitiesAPI = retrofitFactory.create(client, homeServerBaseUrl)
@@ -168,7 +164,7 @@ internal class DefaultGetWellknownTask @Inject constructor(
     }
 
     /**
-     * Return true if identity server is pingable
+     * Return true if identity server is pingable.
      */
     private suspend fun validateIdentityServer(identityServerBaseUrl: String, client: OkHttpClient): Boolean {
         val identityPingApi = retrofitFactory.create(client, identityServerBaseUrl)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/Extensions.kt
index d36e1647139a89e3568dc51a5b29e85249170506..e822c63b564eac300d59ff41b96a8f03900f18fd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/Extensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/Extensions.kt
@@ -20,7 +20,7 @@ import androidx.work.OneTimeWorkRequest
 import org.matrix.android.sdk.internal.session.room.send.NoMerger
 
 /**
- * If startChain parameter is true, the builder will have a inputMerger set to [NoMerger]
+ * If startChain parameter is true, the builder will have a inputMerger set to [NoMerger].
  */
 internal fun OneTimeWorkRequest.Builder.startChain(startChain: Boolean): OneTimeWorkRequest.Builder {
     if (startChain) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt
index e56b359f7ab08537c58effbf8ce9c1955ed13ed9..95b3662c670c6973e2132ba1cc50f378c196a449 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt
@@ -22,11 +22,7 @@ import androidx.work.ListenableWorker
 import androidx.work.WorkerFactory
 import androidx.work.WorkerParameters
 import org.matrix.android.sdk.internal.SessionManager
-import org.matrix.android.sdk.internal.crypto.CancelGossipRequestWorker
-import org.matrix.android.sdk.internal.crypto.SendGossipRequestWorker
-import org.matrix.android.sdk.internal.crypto.SendGossipWorker
 import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
-import org.matrix.android.sdk.internal.crypto.verification.SendVerificationMessageWorker
 import org.matrix.android.sdk.internal.di.MatrixScope
 import org.matrix.android.sdk.internal.session.content.UploadContentWorker
 import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker
@@ -56,8 +52,6 @@ internal class MatrixWorkerFactory @Inject constructor(private val sessionManage
                 CheckFactoryWorker(appContext, workerParameters, true)
             AddPusherWorker::class.java.name                      ->
                 AddPusherWorker(appContext, workerParameters, sessionManager)
-            CancelGossipRequestWorker::class.java.name            ->
-                CancelGossipRequestWorker(appContext, workerParameters, sessionManager)
             GetGroupDataWorker::class.java.name                   ->
                 GetGroupDataWorker(appContext, workerParameters, sessionManager)
             MultipleEventSendingDispatcherWorker::class.java.name ->
@@ -66,12 +60,6 @@ internal class MatrixWorkerFactory @Inject constructor(private val sessionManage
                 RedactEventWorker(appContext, workerParameters, sessionManager)
             SendEventWorker::class.java.name                      ->
                 SendEventWorker(appContext, workerParameters, sessionManager)
-            SendGossipRequestWorker::class.java.name              ->
-                SendGossipRequestWorker(appContext, workerParameters, sessionManager)
-            SendGossipWorker::class.java.name                     ->
-                SendGossipWorker(appContext, workerParameters, sessionManager)
-            SendVerificationMessageWorker::class.java.name        ->
-                SendVerificationMessageWorker(appContext, workerParameters, sessionManager)
             SyncWorker::class.java.name                           ->
                 SyncWorker(appContext, workerParameters, sessionManager)
             UpdateTrustWorker::class.java.name                    ->
@@ -96,9 +84,11 @@ internal class MatrixWorkerFactory @Inject constructor(private val sessionManage
             CoroutineWorker(context, workerParameters) {
 
         // Called by WorkManager if there is no MatrixWorkerFactory
-        constructor(context: Context, workerParameters: WorkerParameters) : this(context,
+        constructor(context: Context, workerParameters: WorkerParameters) : this(
+                context,
                 workerParameters,
-                isCreatedByMatrixWorkerFactory = false)
+                isCreatedByMatrixWorkerFactory = false
+        )
 
         override suspend fun doWork(): Result {
             return if (!isCreatedByMatrixWorkerFactory) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/SessionSafeCoroutineWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/SessionSafeCoroutineWorker.kt
index 334c4580e91dcb254d619a587c18d58fb808a0bd..030f51428ba830fe9d93507d1be67bf9503de9ea 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/SessionSafeCoroutineWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/SessionSafeCoroutineWorker.kt
@@ -69,7 +69,7 @@ internal abstract class SessionSafeCoroutineWorker<PARAM : SessionWorkerParams>(
     abstract fun injectWith(injector: SessionComponent)
 
     /**
-     * Should only return Result.Success for workers added to a unique queue
+     * Should only return Result.Success for workers added to a unique queue.
      */
     abstract suspend fun doSafeWork(params: PARAM): Result
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/SessionWorkerParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/SessionWorkerParams.kt
index de36b85660f0d81766280fe335b0c0b3a9eb8489..36d03f7fcfbf03da6fd0224d3b1ac0208eb64bca 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/SessionWorkerParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/SessionWorkerParams.kt
@@ -18,14 +18,14 @@ package org.matrix.android.sdk.internal.worker
 
 /**
  * Note about the Worker usage:
- * The workers we chain, or when using the append strategy, should never return Result.Failure(), else the chain will be broken forever
+ * The workers we chain, or when using the append strategy, should never return Result.Failure(), else the chain will be broken forever.
  */
 internal interface SessionWorkerParams {
     val sessionId: String
 
     /**
      * Null when no error occurs. When chaining Workers, first step is to check that there is no lastFailureMessage from the previous workers
-     * If it is the case, the worker should just transmit the error and shouldn't do anything else
+     * If it is the case, the worker should just transmit the error and shouldn't do anything else.
      */
     val lastFailureMessage: String?
 }
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/auth/data/VersionsKtTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/auth/data/VersionsKtTest.kt
index 088e16095031cd085e492900a755ae4647fffffe..e1438f47411a4e454601747d5e648f2185af639a 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/auth/data/VersionsKtTest.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/auth/data/VersionsKtTest.kt
@@ -62,12 +62,12 @@ class VersionsKtTest {
         Versions(supportedVersions = listOf("r0.6.0")).doesServerSupportThreads() shouldBe false
         Versions(supportedVersions = listOf("r0.9.1")).doesServerSupportThreads() shouldBe false
         Versions(supportedVersions = listOf("v1.2.0")).doesServerSupportThreads() shouldBe false
-        Versions(supportedVersions = listOf("v1.3.0")).doesServerSupportThreads() shouldBe true
-        Versions(supportedVersions = listOf("v1.3.1")).doesServerSupportThreads() shouldBe true
-        Versions(supportedVersions = listOf("v1.5.1")).doesServerSupportThreads() shouldBe true
+        Versions(supportedVersions = listOf("v1.3.0")).doesServerSupportThreads() shouldBe false
+        Versions(supportedVersions = listOf("v1.3.1")).doesServerSupportThreads() shouldBe false
+        Versions(supportedVersions = listOf("v1.5.1")).doesServerSupportThreads() shouldBe false
         Versions(supportedVersions = listOf("r0.6.0"), unstableFeatures = mapOf("org.matrix.msc3440.stable" to true)).doesServerSupportThreads() shouldBe true
         Versions(supportedVersions = listOf("v1.2.1"), unstableFeatures = mapOf("org.matrix.msc3440.stable" to true)).doesServerSupportThreads() shouldBe true
         Versions(supportedVersions = listOf("r0.6.0"), unstableFeatures = mapOf("org.matrix.msc3440.stable" to false)).doesServerSupportThreads() shouldBe false
-        Versions(supportedVersions = listOf("v1.4.0"), unstableFeatures = mapOf("org.matrix.msc3440.stable" to false)).doesServerSupportThreads() shouldBe true
+        Versions(supportedVersions = listOf("v1.4.0"), unstableFeatures = mapOf("org.matrix.msc3440.stable" to false)).doesServerSupportThreads() shouldBe false
     }
 }
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/pushrules/PushRulesConditionTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/pushrules/PushRulesConditionTest.kt
index 95787173da3af05b95f59f40538e82e940a337d8..c4a3404e80d63dc2ba73abf38d6956b855c455dd 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/pushrules/PushRulesConditionTest.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/session/pushrules/PushRulesConditionTest.kt
@@ -43,7 +43,8 @@ class PushRulesConditionTest : MatrixTest {
                 type = "m.room.message",
                 eventId = "mx0",
                 content = MessageTextContent("m.text", text).toContent(),
-                originServerTs = 0)
+                originServerTs = 0
+        )
     }
 
     @Test
@@ -62,7 +63,8 @@ class PushRulesConditionTest : MatrixTest {
                 eventId = "mx0",
                 stateKey = "@foo:matrix.org",
                 content = rm.toContent(),
-                originServerTs = 0)
+                originServerTs = 0
+        )
 
         assert(condition.isSatisfied(simpleTextEvent))
         assert(!condition.isSatisfied(simpleRoomMemberEvent))
@@ -131,7 +133,8 @@ class PushRulesConditionTest : MatrixTest {
                 eventId = "mx0",
                 content = MessageTextContent("m.notice", "A").toContent(),
                 originServerTs = 0,
-                roomId = "2joined").also {
+                roomId = "2joined"
+        ).also {
             assertTrue("Notice", conditionEqual.isSatisfied(it))
         }
     }
@@ -175,7 +178,8 @@ class PushRulesConditionTest : MatrixTest {
                 eventId = "mx0",
                 content = MessageTextContent("m.text", "A").toContent(),
                 originServerTs = 0,
-                roomId = room2JoinedId).also {
+                roomId = room2JoinedId
+        ).also {
             assertFalse("This room does not have 3 members", conditionEqual3.isSatisfied(it, roomGetterStub))
             assertFalse("This room does not have 3 members", conditionEqual3Bis.isSatisfied(it, roomGetterStub))
             assertTrue("This room has less than 3 members", conditionLessThan3.isSatisfied(it, roomGetterStub))
@@ -186,7 +190,8 @@ class PushRulesConditionTest : MatrixTest {
                 eventId = "mx0",
                 content = MessageTextContent("m.text", "A").toContent(),
                 originServerTs = 0,
-                roomId = room3JoinedId).also {
+                roomId = room3JoinedId
+        ).also {
             assertTrue("This room has 3 members", conditionEqual3.isSatisfied(it, roomGetterStub))
             assertTrue("This room has 3 members", conditionEqual3Bis.isSatisfied(it, roomGetterStub))
             assertFalse("This room has more than 3 members", conditionLessThan3.isSatisfied(it, roomGetterStub))
@@ -206,7 +211,8 @@ class PushRulesConditionTest : MatrixTest {
                 eventId = "mx0",
                 content = MessageTextContent("m.text", "How was the cake benoit?").toContent(),
                 originServerTs = 0,
-                roomId = "2joined")
+                roomId = "2joined"
+        )
 
         condition.isSatisfied(event, "how") shouldBe true
         condition.isSatisfied(event, "How") shouldBe true
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/keysbackup/util/Base58Test.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/keysbackup/util/Base58Test.kt
index a93883a34401a8d03de1a2e1cce8c0132a3ac7ef..e6fe8fbb00f62f61daf45a736552158e29de2352 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/keysbackup/util/Base58Test.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/keysbackup/util/Base58Test.kt
@@ -41,13 +41,17 @@ class Base58Test : MatrixTest {
     @Test
     fun encode_curve25519() {
         // Encode a 32 bytes key
-        assertEquals("4F85ZySpwyY6FuH7mQYyyr5b8nV9zFRBLj92AJa37sMr",
-                base58encode(("0123456789" + "0123456789" + "0123456789" + "01").toByteArray()))
+        assertEquals(
+                "4F85ZySpwyY6FuH7mQYyyr5b8nV9zFRBLj92AJa37sMr",
+                base58encode(("0123456789" + "0123456789" + "0123456789" + "01").toByteArray())
+        )
     }
 
     @Test
     fun decode_curve25519() {
-        assertArrayEquals(("0123456789" + "0123456789" + "0123456789" + "01").toByteArray(),
-                base58decode("4F85ZySpwyY6FuH7mQYyyr5b8nV9zFRBLj92AJa37sMr"))
+        assertArrayEquals(
+                ("0123456789" + "0123456789" + "0123456789" + "01").toByteArray(),
+                base58decode("4F85ZySpwyY6FuH7mQYyyr5b8nV9zFRBLj92AJa37sMr")
+        )
     }
 }
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/keysbackup/util/RecoveryKeyTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/keysbackup/util/RecoveryKeyTest.kt
index d4c9da2986e782882e18071a29558cef3657d374..4146e6b3b70c3fa97387c0aaebc8dfd28726400b 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/keysbackup/util/RecoveryKeyTest.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/keysbackup/util/RecoveryKeyTest.kt
@@ -32,7 +32,8 @@ class RecoveryKeyTest : MatrixTest {
             0x77.toByte(), 0x07.toByte(), 0x6D.toByte(), 0x0A.toByte(), 0x73.toByte(), 0x18.toByte(), 0xA5.toByte(), 0x7D.toByte(),
             0x3C.toByte(), 0x16.toByte(), 0xC1.toByte(), 0x72.toByte(), 0x51.toByte(), 0xB2.toByte(), 0x66.toByte(), 0x45.toByte(),
             0xDF.toByte(), 0x4C.toByte(), 0x2F.toByte(), 0x87.toByte(), 0xEB.toByte(), 0xC0.toByte(), 0x99.toByte(), 0x2A.toByte(),
-            0xB1.toByte(), 0x77.toByte(), 0xFB.toByte(), 0xA5.toByte(), 0x1D.toByte(), 0xB9.toByte(), 0x2C.toByte(), 0x2A.toByte())
+            0xB1.toByte(), 0x77.toByte(), 0xFB.toByte(), 0xA5.toByte(), 0x1D.toByte(), 0xB9.toByte(), 0x2C.toByte(), 0x2A.toByte()
+    )
 
     @Test
     fun isValidRecoveryKey_valid_true() {
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/BinaryStringTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/BinaryStringTest.kt
index 5a82052d1af3c9ddd359f4e72ea26c525d230233..b7951fcc6eab2225afae26dfd01571577de2aeb8 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/BinaryStringTest.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/BinaryStringTest.kt
@@ -26,7 +26,7 @@ import org.matrix.android.sdk.MatrixTest
 class BinaryStringTest : MatrixTest {
 
     /**
-     * I want to put bytes to a String, and vice versa
+     * I want to put bytes to a String, and vice versa.
      */
     @Test
     fun testNominalCase() {
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/pushers/DefaultAddPusherTaskTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/pushers/DefaultAddPusherTaskTest.kt
index 31fd86fe65ecf172a167ac2febfb193973c511ae..32b1d44fb9a5429c25cf1187f358507085b5175e 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/pushers/DefaultAddPusherTaskTest.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/pushers/DefaultAddPusherTaskTest.kt
@@ -81,7 +81,7 @@ class DefaultAddPusherTaskTest {
     }
 
     @Test
-    fun `given a persisted push entity and SetPush API fails when adding Pusher then mutates persisted result with Failed registration state and rethrows error`() {
+    fun `given a persisted push entity and SetPush API fails when adding Pusher then mutates persisted result with Failed registration state and rethrows`() {
         val realmResult = PusherEntity()
         monarchy.givenWhereReturns(result = realmResult)
         pushersAPI.givenSetPusherErrors(SocketException())
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/task/CoroutineSequencersTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/task/CoroutineSequencersTest.kt
index 149b964fd25a09f832732887a6f0334ccc2593fa..0cfd9d97a84dcf48ebc0376deacd7c1808a90066 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/task/CoroutineSequencersTest.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/task/CoroutineSequencersTest.kt
@@ -16,6 +16,8 @@
 
 package org.matrix.android.sdk.internal.task
 
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.asCoroutineDispatcher
 import kotlinx.coroutines.delay
@@ -31,8 +33,8 @@ class CoroutineSequencersTest : MatrixTest {
 
     private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
 
+    @OptIn(DelicateCoroutinesApi::class, ExperimentalCoroutinesApi::class)
     @Test
-    @Suppress("EXPERIMENTAL_API_USAGE")
     fun sequencer_should_run_sequential() {
         val sequencer = SemaphoreCoroutineSequencer()
         val results = ArrayList<String>()
@@ -60,8 +62,8 @@ class CoroutineSequencersTest : MatrixTest {
         assertEquals(results[2], "#3")
     }
 
+    @OptIn(DelicateCoroutinesApi::class, ExperimentalCoroutinesApi::class)
     @Test
-    @Suppress("EXPERIMENTAL_API_USAGE")
     fun sequencer_should_run_parallel() {
         val sequencer1 = SemaphoreCoroutineSequencer()
         val sequencer2 = SemaphoreCoroutineSequencer()
@@ -87,8 +89,8 @@ class CoroutineSequencersTest : MatrixTest {
         assertEquals(3, results.size)
     }
 
+    @OptIn(DelicateCoroutinesApi::class, ExperimentalCoroutinesApi::class)
     @Test
-    @Suppress("EXPERIMENTAL_API_USAGE")
     fun sequencer_should_jump_to_next_when_current_job_canceled() {
         val sequencer = SemaphoreCoroutineSequencer()
         val results = ArrayList<String>()