diff --git a/CHANGES.md b/CHANGES.md
index 5e0467aa9398530c5f658beb434cb0833b65da67..15302c1a2184aebb196e6a7bc0b1293e3880f841 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,30 @@
 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.25 (2022-06-29)
+===================================================
+
+Imported from Element 1.4.25. (https://github.com/vector-im/element-android/releases/tag/v1.4.25)
+
+SDK API changes ⚠️
+------------------
+- Some methods from `Session` have been moved to a new `SyncService`, that you can retrieve from a `Session`.
+- `SyncStatusService` method has been moved to the new `SyncService`
+- `InitSyncStep` have been moved and renamed to `InitialSyncStep`
+- `SyncStatusService.Status` has been renamed to `SyncRequestState`
+- The existing `SyncService` has been renamed to `SyncAndroidService` because of name clash with the new SDK Service ([#6029](https://github.com/vector-im/element-android/issues/6029))
+- Allows `AuthenticationService.getLoginFlow` to fail without resetting state from previously successful calls ([#6093](https://github.com/vector-im/element-android/issues/6093))
+- Allows new passwords to be passed at the point of confirmation when resetting a password ([#6169](https://github.com/vector-im/element-android/issues/6169))
+- Notifies other devices when a verification request sent from an Android device is accepted.` ([#5724](https://github.com/vector-im/element-android/issues/5724))
+- Some `val` have been changed to `fun` to increase their visibility in the generated documentation. Just add `()` if you were using them.
+- `KeysBackupService.state` has been replaced by `KeysBackupService.getState()`
+- `KeysBackupService.isStucked` has been replaced by `KeysBackupService.isStuck()`
+- SDK documentation improved ([#5952](https://github.com/vector-im/element-android/issues/5952))
+- Improve replay attacks and reduce duplicate message index errors ([#6077](https://github.com/vector-im/element-android/issues/6077))
+- Remove `RoomSummaryQueryParams.roomId`. If you need to observe a single room, use the new API `RoomService.getRoomSummaryLive(roomId: String)`
+- `ActiveSpaceFilter` has been renamed to `SpaceFilter`
+- `RoomCategoryFilter.ALL` has been removed, just pass `null` to not filter on Room category. ([#6143](https://github.com/vector-im/element-android/issues/6143))
+
+
 Changes in Matrix-SDK 1.4.16 (2022-05-23)
 ===================================================
 
diff --git a/dependencies.gradle b/dependencies.gradle
index 10f9539e5ac16392be44fd7774c8c397411f9216..451ad4449bc026db99e0f5852244dc49172b1e28 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -7,10 +7,13 @@ ext.versions = [
         'targetCompat'      : JavaVersion.VERSION_11,
 ]
 
-def gradle = "7.2.0"
+
+// Pinned to 7.1.3 because of https://github.com/vector-im/element-android/issues/6142
+// Please test carefully before upgrading again.
+def gradle = "7.1.3"
 // Ref: https://kotlinlang.org/releases.html
 def kotlin = "1.6.21"
-def kotlinCoroutines = "1.6.1"
+def kotlinCoroutines = "1.6.2"
 def dagger = "2.42"
 def retrofit = "2.9.0"
 def arrow = "0.8.2"
@@ -23,7 +26,7 @@ def mavericks = "2.6.1"
 def glide = "4.13.2"
 def bigImageViewer = "1.8.1"
 def jjwt = "0.11.5"
-def vanniktechEmoji = "0.9.0"
+def vanniktechEmoji = "0.15.0"
 
 // Testing
 def mockk = "1.12.4"
@@ -45,12 +48,13 @@ ext.libs = [
                 'coroutinesTest'          : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines"
         ],
         androidx    : [
-                'appCompat'               : "androidx.appcompat:appcompat:1.4.1",
-                'core'                    : "androidx.core:core-ktx:1.7.0",
+                'activity'                : "androidx.activity:activity:1.4.0",
+                'appCompat'               : "androidx.appcompat:appcompat:1.4.2",
+                'core'                    : "androidx.core:core-ktx:1.8.0",
                 'recyclerview'            : "androidx.recyclerview:recyclerview:1.2.1",
                 'exifinterface'           : "androidx.exifinterface:exifinterface:1.3.3",
                 'fragmentKtx'             : "androidx.fragment:fragment-ktx:1.4.1",
-                'constraintLayout'        : "androidx.constraintlayout:constraintlayout:2.1.3",
+                'constraintLayout'        : "androidx.constraintlayout:constraintlayout:2.1.4",
                 'work'                    : "androidx.work:work-runtime-ktx:2.7.1",
                 'autoFill'                : "androidx.autofill:autofill:1.1.0",
                 'preferenceKtx'           : "androidx.preference:preference-ktx:1.2.0",
@@ -69,10 +73,12 @@ ext.libs = [
                 'testRules'               : "androidx.test:rules:$androidxTest",
                 'espressoCore'            : "androidx.test.espresso:espresso-core:$espresso",
                 'espressoContrib'         : "androidx.test.espresso:espresso-contrib:$espresso",
-                'espressoIntents'         : "androidx.test.espresso:espresso-intents:$espresso"
+                'espressoIntents'         : "androidx.test.espresso:espresso-intents:$espresso",
+                'viewpager2'              : "androidx.viewpager2:viewpager2:1.0.0",
+                'transition'              : "androidx.transition:transition:1.2.0",
         ],
         google      : [
-                'material'                : "com.google.android.material:material:1.6.0"
+                'material'                : "com.google.android.material:material:1.6.1"
         ],
         dagger      : [
                 'dagger'                  : "com.google.dagger:dagger:$dagger",
@@ -81,7 +87,7 @@ ext.libs = [
                 'hiltCompiler'            : "com.google.dagger:hilt-compiler:$dagger"
         ],
         squareup    : [
-                'moshi'                  : "com.squareup.moshi:moshi-adapters:$moshi",
+                'moshi'                  : "com.squareup.moshi:moshi:$moshi",
                 'moshiKotlin'            : "com.squareup.moshi:moshi-kotlin-codegen:$moshi",
                 'retrofit'               : "com.squareup.retrofit2:retrofit:$retrofit",
                 'retrofitMoshi'          : "com.squareup.retrofit2:converter-moshi:$retrofit"
@@ -107,6 +113,10 @@ ext.libs = [
                 'mavericks'              : "com.airbnb.android:mavericks:$mavericks",
                 'mavericksTesting'       : "com.airbnb.android:mavericks-testing:$mavericks"
         ],
+        maplibre    : [
+                'androidSdk'             : "org.maplibre.gl:android-sdk:9.5.2",
+                'pluginAnnotation'       : "org.maplibre.gl:android-plugin-annotation-v9:1.0.0"
+        ],
         mockk      : [
                 'mockk'                   : "io.mockk:mockk:$mockk",
                 'mockkAndroid'            : "io.mockk:mockk-android:$mockk"
diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle
index 76869fccf1c70d38dcafb076c1b239498b3a8fea..59cefe7e899545202918938527213805f5982217 100644
--- a/dependencies_groups.gradle
+++ b/dependencies_groups.gradle
@@ -141,7 +141,6 @@ ext.groups = [
                         'jline',
                         'jp.wasabeef',
                         'junit',
-                        'me.leolin',
                         'me.saket',
                         'net.bytebuddy',
                         'net.java',
diff --git a/gradle.properties b/gradle.properties
index 97384e645c0a6dbdf353943d4d298f288515ce73..fc230026271373424a89d4e1cc904f4cf48bcc7d 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.16
+VERSION_NAME=1.4.25
 
 POM_PACKAGING=aar
 
diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle
index d04a675cbaa67e173db8b91b14a0622e057d27c3..f6a7a294de26955a5ed883525332809aea9a93f4 100644
--- a/matrix-sdk-android/build.gradle
+++ b/matrix-sdk-android/build.gradle
@@ -77,6 +77,7 @@ android {
 
     buildTypes {
         debug {
+            testCoverageEnabled true
             // Set to true to log privacy or sensible data, such as token
             buildConfigField "boolean", "LOG_PRIVATE_DATA", project.property("vector.debugPrivateData")
             // Set to BODY instead of NONE to enable logging
@@ -139,7 +140,6 @@ dependencies {
     implementation libs.jetbrains.coroutinesCore
     implementation libs.jetbrains.coroutinesAndroid
 
-    implementation libs.androidx.appCompat
     implementation libs.androidx.core
 
     // Lifecycle
@@ -155,15 +155,14 @@ dependencies {
     // - https://github.com/square/okhttp/issues/3278
     // - https://github.com/square/okhttp/issues/4455
     // - https://github.com/square/okhttp/issues/3146
-    implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3"))
+    implementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))
     implementation 'com.squareup.okhttp3:okhttp'
     implementation 'com.squareup.okhttp3:logging-interceptor'
-    implementation 'com.squareup.okhttp3:okhttp-urlconnection'
 
     implementation libs.squareup.moshi
     kapt libs.squareup.moshiKotlin
 
-    implementation libs.markwon.core
+    api "com.atlassian.commonmark:commonmark:0.13.0"
 
     // Image
     implementation libs.androidx.exifinterface
@@ -179,12 +178,8 @@ dependencies {
     // Work
     implementation libs.androidx.work
 
-    // FP
-    implementation libs.arrow.core
-    implementation libs.arrow.instances
-
     // olm lib is now hosted in MavenCentral
-    implementation 'org.matrix.android:olm-sdk:3.2.11'
+    implementation 'org.matrix.android:olm-sdk:3.2.12'
 
     // DI
     implementation libs.dagger.dagger
@@ -201,11 +196,9 @@ dependencies {
     implementation libs.apache.commonsImaging
 
     // Phone number https://github.com/google/libphonenumber
-    implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.48'
+    implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.50'
 
     testImplementation libs.tests.junit
-    testImplementation 'org.robolectric:robolectric:4.7.3'
-    //testImplementation 'org.robolectric:shadows-support-v4:3.0'
     // Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
     testImplementation libs.mockk.mockk
     testImplementation libs.tests.kluent
diff --git a/matrix-sdk-android/docs/packages.md b/matrix-sdk-android/docs/packages.md
index ae7bee1b4e0c8fb954fc39629e87dc79aafa26fd..19f7c15a7a557396dc08ca7e8aa2df5340b4de93 100644
--- a/matrix-sdk-android/docs/packages.md
+++ b/matrix-sdk-android/docs/packages.md
@@ -1,3 +1,7 @@
+# Package org.matrix.android.sdk.userstories
+
+This package contains some user stories (**Us** prefix) of the SDK usage. You will find example of what it is possible to do with the SDK and the API which can be used to do it.
+
 # Package org.matrix.android.sdk.api
 
 This is the root package of the API exposed by this SDK.
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/InstrumentedTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/InstrumentedTest.kt
index a76376682107df2000398d66e5281b4e99e4ef73..f08f0a28ed1569cf86b0e8f345cc3d8fe1b771d1 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/InstrumentedTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/InstrumentedTest.kt
@@ -19,10 +19,14 @@ package org.matrix.android.sdk
 import android.content.Context
 import androidx.test.core.app.ApplicationProvider
 import org.junit.Rule
+import org.matrix.android.sdk.common.RetryTestRule
 import org.matrix.android.sdk.test.shared.createTimberTestRule
 
 interface InstrumentedTest {
 
+    @Rule
+    fun retryTestRule() = RetryTestRule(3)
+
     @Rule
     fun timberTestRule() = createTimberTestRule()
 
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/Util.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/Util.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5e2c2ba25fe84b05c064433168c07d66ad07e2bb
--- /dev/null
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/Util.kt
@@ -0,0 +1,44 @@
+/*
+ * 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
+
+import junit.framework.TestCase.fail
+
+/**
+ * Will fail the test if invoking [block] is not throwing a Throwable.
+ *
+ * @param message the failure message, if the block does not throw any Throwable
+ * @param failureBlock a Lambda to be able to do extra check on the thrown Throwable
+ * @param block the block to test
+ */
+internal suspend fun mustFail(
+        message: String = "must fail",
+        failureBlock: ((Throwable) -> Unit)? = null,
+        block: suspend () -> Unit,
+) {
+    val isSuccess = try {
+        block.invoke()
+        true
+    } catch (throwable: Throwable) {
+        failureBlock?.invoke(throwable)
+        false
+    }
+
+    if (isSuccess) {
+        fail(message)
+    }
+}
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/AccountCreationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/AccountCreationTest.kt
index 486bc0276950b0a50195818ac3e20984cf00effc..7e4fc4768fba85909885f3e7faeb506a267ef7e8 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/AccountCreationTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/AccountCreationTest.kt
@@ -24,8 +24,8 @@ import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 import org.junit.runners.MethodSorters
 import org.matrix.android.sdk.InstrumentedTest
-import org.matrix.android.sdk.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
 import org.matrix.android.sdk.common.SessionTestParams
 import org.matrix.android.sdk.common.TestConstants
 
@@ -34,32 +34,22 @@ import org.matrix.android.sdk.common.TestConstants
 @LargeTest
 class AccountCreationTest : InstrumentedTest {
 
-    private val commonTestHelper = CommonTestHelper(context())
-    private val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
-
     @Test
-    fun createAccountTest() {
-        val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
-
-        commonTestHelper.signOutAndClose(session)
+    fun createAccountTest() = runSessionTest(context()) { commonTestHelper ->
+        commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
     }
 
     @Test
     @Ignore("This test will be ignored until it is fixed")
-    fun createAccountAndLoginAgainTest() {
+    fun createAccountAndLoginAgainTest() = runSessionTest(context()) { commonTestHelper ->
         val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
 
         // Log again to the same account
-        val session2 = commonTestHelper.logIntoAccount(session.myUserId, SessionTestParams(withInitialSync = true))
-
-        commonTestHelper.signOutAndClose(session)
-        commonTestHelper.signOutAndClose(session2)
+        commonTestHelper.logIntoAccount(session.myUserId, SessionTestParams(withInitialSync = true))
     }
 
     @Test
-    fun simpleE2eTest() {
-        val res = cryptoTestHelper.doE2ETestWithAliceInARoom()
-
-        res.cleanUp(commonTestHelper)
+    fun simpleE2eTest() = runCryptoTest(context()) { cryptoTestHelper, _ ->
+        cryptoTestHelper.doE2ETestWithAliceInARoom()
     }
 }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt
index 6d740c5a3421c5668b3fb13c5583f69ebe980944..260e8dbe058bb7d73ee87d1409fcd61cfa8cde8b 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt
@@ -25,7 +25,7 @@ import org.junit.runners.JUnit4
 import org.junit.runners.MethodSorters
 import org.matrix.android.sdk.InstrumentedTest
 import org.matrix.android.sdk.api.failure.isInvalidPassword
-import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
 import org.matrix.android.sdk.common.SessionTestParams
 import org.matrix.android.sdk.common.TestConstants
 
@@ -34,14 +34,12 @@ import org.matrix.android.sdk.common.TestConstants
 @Ignore("This test will be ignored until it is fixed")
 class ChangePasswordTest : InstrumentedTest {
 
-    private val commonTestHelper = CommonTestHelper(context())
-
     companion object {
         private const val NEW_PASSWORD = "this is a new password"
     }
 
     @Test
-    fun changePasswordTest() {
+    fun changePasswordTest() = runSessionTest(context()) { commonTestHelper ->
         val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false))
 
         // Change password
@@ -54,9 +52,6 @@ class ChangePasswordTest : InstrumentedTest {
         throwable.isInvalidPassword().shouldBeTrue()
 
         // Try to login with the new password, should work
-        val session2 = commonTestHelper.logIntoAccount(session.myUserId, NEW_PASSWORD, SessionTestParams(withInitialSync = false))
-
-        commonTestHelper.signOutAndClose(session)
-        commonTestHelper.signOutAndClose(session2)
+        commonTestHelper.logIntoAccount(session.myUserId, NEW_PASSWORD, SessionTestParams(withInitialSync = false))
     }
 }
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 d2dfe4d9454b2f02d44602a39b185398deb29054..0b21f85742d513bfac201c648958a4990e8b099f 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
@@ -29,7 +29,7 @@ import org.matrix.android.sdk.api.auth.UserPasswordAuth
 import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.MatrixError
-import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
 import org.matrix.android.sdk.common.SessionTestParams
 import org.matrix.android.sdk.common.TestConstants
 import kotlin.coroutines.Continuation
@@ -39,10 +39,8 @@ import kotlin.coroutines.resume
 @FixMethodOrder(MethodSorters.JVM)
 class DeactivateAccountTest : InstrumentedTest {
 
-    private val commonTestHelper = CommonTestHelper(context())
-
     @Test
-    fun deactivateAccountTest() {
+    fun deactivateAccountTest() = runSessionTest(context(), false /* session will be deactivated */) { commonTestHelper ->
         val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
 
         // Deactivate the account
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/network/ApiInterceptorTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/network/ApiInterceptorTest.kt
index 9371154aaf0aee016ab47dfccadc11e126aab846..8dbff82015791b6fa43f92d94e38eb85d542f28f 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/network/ApiInterceptorTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/network/ApiInterceptorTest.kt
@@ -23,7 +23,7 @@ import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 import org.junit.runners.MethodSorters
 import org.matrix.android.sdk.InstrumentedTest
-import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
 import org.matrix.android.sdk.common.SessionTestParams
 import org.matrix.android.sdk.common.TestConstants
 import timber.log.Timber
@@ -32,10 +32,8 @@ import timber.log.Timber
 @FixMethodOrder(MethodSorters.JVM)
 class ApiInterceptorTest : InstrumentedTest {
 
-    private val commonTestHelper = CommonTestHelper(context())
-
     @Test
-    fun apiInterceptorTest() {
+    fun apiInterceptorTest() = runSessionTest(context()) { commonTestHelper ->
         val responses = mutableListOf<String>()
 
         val listener = object : ApiInterceptorListener {
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 e33e4faea2920db2b6e75956254bcb42dac6eff5..7dafe33935f0c84baec58743f05208b1d4d9266e 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
@@ -54,12 +54,39 @@ import java.util.concurrent.TimeUnit
  * This class exposes methods to be used in common cases
  * Registration, login, Sync, Sending messages...
  */
-class CommonTestHelper(context: Context) {
+class CommonTestHelper private constructor(context: Context) {
+
+    companion object {
+        internal fun runSessionTest(context: Context, autoSignoutOnClose: Boolean = true, block: (CommonTestHelper) -> Unit) {
+            val testHelper = CommonTestHelper(context)
+            return try {
+                block(testHelper)
+            } finally {
+                if (autoSignoutOnClose) {
+                    testHelper.cleanUpOpenedSessions()
+                }
+            }
+        }
+
+        internal fun runCryptoTest(context: Context, autoSignoutOnClose: Boolean = true, block: (CryptoTestHelper, CommonTestHelper) -> Unit) {
+            val testHelper = CommonTestHelper(context)
+            val cryptoTestHelper = CryptoTestHelper(testHelper)
+            return try {
+                block(cryptoTestHelper, testHelper)
+            } finally {
+                if (autoSignoutOnClose) {
+                    testHelper.cleanUpOpenedSessions()
+                }
+            }
+        }
+    }
 
     internal val matrix: TestMatrix
     private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
     private var accountNumber = 0
 
+    private val trackedSessions = mutableListOf<Session>()
+
     fun getTestInterceptor(session: Session): MockOkHttpInterceptor? = TestModule.interceptorForSession(session.sessionId) as? MockOkHttpInterceptor
 
     init {
@@ -84,6 +111,15 @@ class CommonTestHelper(context: Context) {
         return logIntoAccount(userId, TestConstants.PASSWORD, testParams)
     }
 
+    fun cleanUpOpenedSessions() {
+        trackedSessions.forEach {
+            runBlockingTest {
+                it.signOutService().signOut(true)
+            }
+        }
+        trackedSessions.clear()
+    }
+
     /**
      * Create a homeserver configuration, with Http connection allowed for test
      */
@@ -96,16 +132,16 @@ class CommonTestHelper(context: Context) {
     /**
      * This methods init the event stream and check for initial sync
      *
-     * @param session    the session to sync
+     * @param session the session to sync
      */
     fun syncSession(session: Session, timeout: Long = TestConstants.timeOutMillis * 10) {
         val lock = CountDownLatch(1)
         coroutineScope.launch {
-            session.startSync(true)
-            val syncLiveData = session.getSyncStateLive()
+            session.syncService().startSync(true)
+            val syncLiveData = session.syncService().getSyncStateLive()
             val syncObserver = object : Observer<SyncState> {
                 override fun onChanged(t: SyncState?) {
-                    if (session.hasAlreadySynced()) {
+                    if (session.syncService().hasAlreadySynced()) {
                         lock.countDown()
                         syncLiveData.removeObserver(this)
                     }
@@ -119,15 +155,15 @@ class CommonTestHelper(context: Context) {
     /**
      * This methods clear the cache and waits for initialSync
      *
-     * @param session    the session to sync
+     * @param session the session to sync
      */
     fun clearCacheAndSync(session: Session, timeout: Long = TestConstants.timeOutMillis) {
         waitWithLatch(timeout) { latch ->
             session.clearCache()
-            val syncLiveData = session.getSyncStateLive()
+            val syncLiveData = session.syncService().getSyncStateLive()
             val syncObserver = object : Observer<SyncState> {
                 override fun onChanged(t: SyncState?) {
-                    if (session.hasAlreadySynced()) {
+                    if (session.syncService().hasAlreadySynced()) {
                         Timber.v("Clear cache and synced")
                         syncLiveData.removeObserver(this)
                         latch.countDown()
@@ -135,15 +171,15 @@ class CommonTestHelper(context: Context) {
                 }
             }
             syncLiveData.observeForever(syncObserver)
-            session.startSync(true)
+            session.syncService().startSync(true)
         }
     }
 
     /**
      * Sends text messages in a room
      *
-     * @param room         the room where to send the messages
-     * @param message      the message to send
+     * @param room the room where to send the messages
+     * @param message the message to send
      * @param nbOfMessages the number of time the message will be sent
      */
     fun sendTextMessage(room: Room, message: String, nbOfMessages: Int, timeout: Long = TestConstants.timeOutMillis): List<TimelineEvent> {
@@ -207,8 +243,8 @@ class CommonTestHelper(context: Context) {
 
     /**
      * Reply in a thread
-     * @param room         the room where to send the messages
-     * @param message      the message to send
+     * @param room the room where to send the messages
+     * @param message the message to send
      * @param numberOfMessages the number of time the message will be sent
      */
     fun replyInThreadMessage(
@@ -216,7 +252,8 @@ class CommonTestHelper(context: Context) {
             message: String,
             numberOfMessages: Int,
             rootThreadEventId: String,
-            timeout: Long = TestConstants.timeOutMillis): List<TimelineEvent> {
+            timeout: Long = TestConstants.timeOutMillis
+    ): List<TimelineEvent> {
         val timeline = room.timelineService().createTimeline(null, TimelineSettings(10))
         timeline.start()
         val sentEvents = sendTextMessagesBatched(timeline, room, message, numberOfMessages, timeout, rootThreadEventId)
@@ -232,48 +269,58 @@ class CommonTestHelper(context: Context) {
      * Creates a unique account
      *
      * @param userNamePrefix the user name prefix
-     * @param password       the password
-     * @param testParams     test params about the session
+     * @param password the password
+     * @param testParams test params about the session
      * @return the session associated with the newly created account
      */
-    private fun createAccount(userNamePrefix: String,
-                              password: String,
-                              testParams: SessionTestParams): Session {
+    private fun createAccount(
+            userNamePrefix: String,
+            password: String,
+            testParams: SessionTestParams
+    ): Session {
         val session = createAccountAndSync(
                 userNamePrefix + "_" + accountNumber++ + "_" + UUID.randomUUID(),
                 password,
                 testParams
         )
         assertNotNull(session)
-        return session
+        return session.also {
+            trackedSessions.add(session)
+        }
     }
 
     /**
      * Logs into an existing account
      *
-     * @param userId     the userId to log in
-     * @param password   the password to log in
+     * @param userId the userId to log in
+     * @param password the password to log in
      * @param testParams test params about the session
      * @return the session associated with the existing account
      */
-    fun logIntoAccount(userId: String,
-                       password: String,
-                       testParams: SessionTestParams): Session {
+    fun logIntoAccount(
+            userId: String,
+            password: String,
+            testParams: SessionTestParams
+    ): Session {
         val session = logAccountAndSync(userId, password, testParams)
         assertNotNull(session)
-        return session
+        return session.also {
+            trackedSessions.add(session)
+        }
     }
 
     /**
      * Create an account and a dedicated session
      *
-     * @param userName          the account username
-     * @param password          the password
+     * @param userName the account username
+     * @param password the password
      * @param sessionTestParams parameters for the test
      */
-    private fun createAccountAndSync(userName: String,
-                                     password: String,
-                                     sessionTestParams: SessionTestParams): Session {
+    private fun createAccountAndSync(
+            userName: String,
+            password: String,
+            sessionTestParams: SessionTestParams
+    ): Session {
         val hs = createHomeServerConfig()
 
         runBlockingTest {
@@ -297,7 +344,7 @@ class CommonTestHelper(context: Context) {
         val session = (registrationResult as RegistrationResult.Success).session
         session.open()
         if (sessionTestParams.withInitialSync) {
-            syncSession(session, 60_000)
+            syncSession(session, 120_000)
         }
         return session
     }
@@ -305,13 +352,15 @@ class CommonTestHelper(context: Context) {
     /**
      * Start an account login
      *
-     * @param userName          the account username
-     * @param password          the password
+     * @param userName the account username
+     * @param password the password
      * @param sessionTestParams session test params
      */
-    private fun logAccountAndSync(userName: String,
-                                  password: String,
-                                  sessionTestParams: SessionTestParams): Session {
+    private fun logAccountAndSync(
+            userName: String,
+            password: String,
+            sessionTestParams: SessionTestParams
+    ): Session {
         val hs = createHomeServerConfig()
 
         runBlockingTest {
@@ -337,8 +386,10 @@ class CommonTestHelper(context: Context) {
      * @param userName the account username
      * @param password the password
      */
-    fun logAccountWithError(userName: String,
-                            password: String): Throwable {
+    fun logAccountWithError(
+            userName: String,
+            password: String
+    ): Throwable {
         val hs = createHomeServerConfig()
 
         runBlockingTest {
@@ -378,7 +429,10 @@ class CommonTestHelper(context: Context) {
      * @throws InterruptedException
      */
     fun await(latch: CountDownLatch, timeout: Long? = TestConstants.timeOutMillis) {
-        assertTrue(latch.await(timeout ?: TestConstants.timeOutMillis, TimeUnit.MILLISECONDS))
+        assertTrue(
+                "Timed out after " + timeout + "ms waiting for something to happen. See stacktrace for cause.",
+                latch.await(timeout ?: TestConstants.timeOutMillis, TimeUnit.MILLISECONDS)
+        )
     }
 
     suspend fun retryPeriodicallyWithLatch(latch: CountDownLatch, condition: (() -> Boolean)) {
@@ -433,6 +487,7 @@ class CommonTestHelper(context: Context) {
     fun Iterable<Session>.signOutAndClose() = forEach { signOutAndClose(it) }
 
     fun signOutAndClose(session: Session) {
+        trackedSessions.remove(session)
         runBlockingTest(timeout = 60_000) {
             session.signOutService().signOut(true)
         }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestData.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestData.kt
index b6bedbd7197eff6d73c3d54a063600b81f463791..41d0d3a7e86810386ee6ddfa2bcf43d2517195e0 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestData.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestData.kt
@@ -18,8 +18,10 @@ package org.matrix.android.sdk.common
 
 import org.matrix.android.sdk.api.session.Session
 
-data class CryptoTestData(val roomId: String,
-                          val sessions: List<Session>) {
+data class CryptoTestData(
+        val roomId: String,
+        val sessions: List<Session>
+) {
 
     val firstSession: Session
         get() = sessions.first()
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 348841313b5f9f5fd6f73d9f551a0c1edfc80f79..5fd86d4fdb87ec58d9d6481ab97138d8cdf79dde 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
@@ -58,7 +58,7 @@ 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.session.securestorage.KeyRef
 import org.matrix.android.sdk.api.util.Optional
 import org.matrix.android.sdk.api.util.awaitCallback
 import org.matrix.android.sdk.api.util.toBase64NoPadding
@@ -66,7 +66,7 @@ import java.util.UUID
 import kotlin.coroutines.Continuation
 import kotlin.coroutines.resume
 
-class CryptoTestHelper(private val testHelper: CommonTestHelper) {
+class CryptoTestHelper(val testHelper: CommonTestHelper) {
 
     private val messagesFromAlice: List<String> = listOf("0 - Hello I'm Alice!", "4 - Go!")
     private val messagesFromBob: List<String> = listOf("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera.")
@@ -361,19 +361,19 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
             ssssService.storeSecret(
                     MASTER_KEY_SSSS_NAME,
                     session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.master!!,
-                    listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec))
+                    listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec))
             )
 
             ssssService.storeSecret(
                     SELF_SIGNING_KEY_SSSS_NAME,
                     session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.selfSigned!!,
-                    listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec))
+                    listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec))
             )
 
             ssssService.storeSecret(
                     USER_SIGNING_KEY_SSSS_NAME,
                     session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.user!!,
-                    listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec))
+                    listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec))
             )
 
             // set up megolm backup
@@ -390,7 +390,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
                 ssssService.storeSecret(
                         KEYBACKUP_SECRET_SSSS_NAME,
                         secret,
-                        listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec))
+                        listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec))
                 )
             }
         }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/MockOkHttpInterceptor.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/MockOkHttpInterceptor.kt
index b6d833a77cd5d04239969520472ab9ffaa3e5295..6dfee2f18f226119ae2279758f0fb5c2815a8a2a 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/MockOkHttpInterceptor.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/MockOkHttpInterceptor.kt
@@ -73,9 +73,11 @@ class MockOkHttpInterceptor : TestInterceptor {
     /**
      * Simple rule that reply with the given body for any request that matches the match param
      */
-    class SimpleRule(match: String,
-                     private val code: Int = HttpsURLConnection.HTTP_OK,
-                     private val body: String = "{}") : Rule(match) {
+    class SimpleRule(
+            match: String,
+            private val code: Int = HttpsURLConnection.HTTP_OK,
+            private val body: String = "{}"
+    ) : Rule(match) {
 
         override fun process(originalRequest: Request): Response? {
             return Response.Builder()
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/RetryTestRule.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/RetryTestRule.kt
index b16ab98e6c9fc69d9af8c91be067e196a7cca7a5..39f49a9ccc3f96b3d13e03f79b3d8fc6099da4c3 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/RetryTestRule.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/RetryTestRule.kt
@@ -40,6 +40,9 @@ class RetryTestRule(val retryCount: Int = 3) : TestRule {
                 for (i in 0 until retryCount) {
                     try {
                         base.evaluate()
+                        if (i > 0) {
+                            println("Retried test $i times")
+                        }
                         return
                     } catch (t: Throwable) {
                         caughtThrowable = t
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestConstants.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestConstants.kt
index 0f79896b2cd28a6f42bdc7fd19ded9a3a15c1dbf..89c965c31affc59685d4662848cbec6ee1ec74d4 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestConstants.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestConstants.kt
@@ -23,7 +23,7 @@ object TestConstants {
     const val TESTS_HOME_SERVER_URL = "http://10.0.2.2:8080"
 
     // Time out to use when waiting for server response.
-    private const val AWAIT_TIME_OUT_MILLIS = 60_000
+    private const val AWAIT_TIME_OUT_MILLIS = 120_000
 
     // Time out to use when waiting for server response, when the debugger is connected. 10 minutes
     private const val AWAIT_TIME_OUT_WITH_DEBUGGER_MILLIS = 10 * 60_000
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 e663cc186571b539fbde872f1c10331c1aec5f37..5864a801e654534ca6058978e3b29798beeff055 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
@@ -21,7 +21,8 @@ import android.os.Handler
 import android.os.Looper
 import androidx.lifecycle.ProcessLifecycleOwner
 import androidx.work.Configuration
-import androidx.work.WorkManager
+import androidx.work.impl.WorkManagerImpl
+import androidx.work.impl.utils.taskexecutor.WorkManagerTaskExecutor
 import com.zhuinden.monarchy.Monarchy
 import org.matrix.android.sdk.BuildConfig
 import org.matrix.android.sdk.api.MatrixConfiguration
@@ -66,7 +67,12 @@ internal class TestMatrix(context: Context, matrixConfiguration: MatrixConfigura
                 .setExecutor(Executors.newCachedThreadPool())
                 .setWorkerFactory(matrixWorkerFactory)
                 .build()
-        WorkManager.initialize(appContext, configuration)
+        val delegate = WorkManagerImpl(
+                context,
+                configuration,
+                WorkManagerTaskExecutor(configuration.taskExecutor)
+        )
+        WorkManagerImpl.setDelegate(delegate)
         uiHandler.post {
             ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
         }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixCallback.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixCallback.kt
index 9f6d6eb1368fc2e88ec669bc287677b485413fc2..a007d684e326f6df3c9584205814779929ff5707 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixCallback.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixCallback.kt
@@ -27,8 +27,10 @@ import java.util.concurrent.CountDownLatch
  * @param onlySuccessful true to fail if an error occurs. This is the default behavior
  * @param <T>
  */
-open class TestMatrixCallback<T>(private val countDownLatch: CountDownLatch,
-                                 private val onlySuccessful: Boolean = true) : MatrixCallback<T> {
+open class TestMatrixCallback<T>(
+        private val countDownLatch: CountDownLatch,
+        private val onlySuccessful: Boolean = true
+) : MatrixCallback<T> {
 
     @CallSuper
     override fun onSuccess(data: T) {
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 525e168cf1f2a19170d74ba0547a4551e70ff23e..daf6b73313fd900db73e8fde539321714fafba6e 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
@@ -47,7 +47,9 @@ internal interface TestMatrixComponent : MatrixComponent {
 
     @Component.Factory
     interface Factory {
-        fun create(@BindsInstance context: Context,
-                   @BindsInstance matrixConfiguration: MatrixConfiguration): TestMatrixComponent
+        fun create(
+                @BindsInstance context: Context,
+                @BindsInstance matrixConfiguration: MatrixConfiguration
+        ): TestMatrixComponent
     }
 }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt
index f5f585a1e0c9f6e4daa9194220962fc5349e8f16..17c7c28d81dffcb80438b4854e44a52d07ef46d3 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt
@@ -22,6 +22,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertNotEquals
 import org.junit.FixMethodOrder
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -40,6 +41,7 @@ import java.util.UUID
 @Suppress("SpellCheckingInspection")
 @RunWith(AndroidJUnit4::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Ignore
 class AttachmentEncryptionTest {
 
     private fun checkDecryption(input: String, encryptedFileInfo: EncryptedFileInfo): String {
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 e823aa39a1115124acc2daf9d9918e4a834a3bd6..dbc6929e34865bc07d1d28e09a5a6bfae57fef2e 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
@@ -22,9 +22,12 @@ import org.junit.Assert.assertEquals
 import org.junit.Assert.assertNotEquals
 import org.junit.Assert.assertNull
 import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.matrix.android.sdk.InstrumentedTest
+import org.matrix.android.sdk.common.RetryTestRule
 import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import org.matrix.android.sdk.internal.util.time.DefaultClock
@@ -35,8 +38,11 @@ import org.matrix.olm.OlmSession
 private const val DUMMY_DEVICE_KEY = "DeviceKey"
 
 @RunWith(AndroidJUnit4::class)
+@Ignore
 class CryptoStoreTest : InstrumentedTest {
 
+    @get:Rule val rule = RetryTestRule(3)
+
     private val cryptoStoreHelper = CryptoStoreHelper()
     private val clock = DefaultClock()
 
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/DecryptRedactedEventTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/DecryptRedactedEventTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a48b45a1f53fb78b819c310679fc274dc90aee20
--- /dev/null
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/DecryptRedactedEventTest.kt
@@ -0,0 +1,75 @@
+/*
+ * 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 androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Assert
+import org.junit.FixMethodOrder
+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.session.events.model.Event
+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.common.CommonTestHelper.Companion.runCryptoTest
+
+@RunWith(AndroidJUnit4::class)
+@FixMethodOrder(MethodSorters.JVM)
+class DecryptRedactedEventTest : InstrumentedTest {
+
+    @Test
+    fun doNotFailToDecryptRedactedEvent() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
+        val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
+        val e2eRoomID = testData.roomId
+        val aliceSession = testData.firstSession
+        val bobSession = testData.secondSession!!
+
+        val roomALicePOV = aliceSession.getRoom(e2eRoomID)!!
+        val timelineEvent = testHelper.sendTextMessage(roomALicePOV, "Hello", 1).first()
+        val redactionReason = "Wrong Room"
+        roomALicePOV.sendService().redactEvent(timelineEvent.root, redactionReason)
+
+        // get the event from bob
+        testHelper.waitWithLatch {
+            testHelper.retryPeriodicallyWithLatch(it) {
+                bobSession.getRoom(e2eRoomID)?.getTimelineEvent(timelineEvent.eventId)?.root?.isRedacted() == true
+            }
+        }
+
+        val eventBobPov = bobSession.getRoom(e2eRoomID)?.getTimelineEvent(timelineEvent.eventId)!!
+
+        testHelper.runBlockingTest {
+            try {
+                val result = bobSession.cryptoService().decryptEvent(eventBobPov.root, "")
+                Assert.assertEquals(
+                        "Unexpected redacted reason",
+                        redactionReason,
+                        result.clearEvent.toModel<Event>()?.unsignedData?.redactedEvent?.content?.get("reason")
+                )
+                Assert.assertEquals(
+                        "Unexpected Redacted event id",
+                        timelineEvent.eventId,
+                        result.clearEvent.toModel<Event>()?.unsignedData?.redactedEvent?.redacts
+                )
+            } catch (failure: Throwable) {
+                Assert.fail("Should not throw when decrypting a redacted event")
+            }
+        }
+    }
+}
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 ebe4c5ff6fb52e2408650ed722173309a4236712..5a61eee7fe30c238ddfd410e318c9a901999a980 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
@@ -23,6 +23,8 @@ import org.amshove.kluent.fail
 import org.amshove.kluent.internal.assertEquals
 import org.junit.Assert
 import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -56,17 +58,23 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent
 import org.matrix.android.sdk.api.session.room.send.SendState
 import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
 import org.matrix.android.sdk.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
+import org.matrix.android.sdk.common.RetryTestRule
 import org.matrix.android.sdk.common.SessionTestParams
 import org.matrix.android.sdk.common.TestConstants
 import org.matrix.android.sdk.common.TestMatrixCallback
+import org.matrix.android.sdk.mustFail
 import java.util.concurrent.CountDownLatch
 
 @RunWith(JUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
 @LargeTest
+@Ignore("This test fails with an unhandled exception thrown from a coroutine which terminates the entire test run.")
 class E2eeSanityTests : InstrumentedTest {
 
+    @get:Rule val rule = RetryTestRule(3)
+
     /**
      * Simple test that create an e2ee room.
      * Some new members are added, and a message is sent.
@@ -77,9 +85,7 @@ class E2eeSanityTests : InstrumentedTest {
      * Alice sends a new message, then check that the new one can be decrypted
      */
     @Test
-    fun testSendingE2EEMessages() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun testSendingE2EEMessages() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
 
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
         val aliceSession = cryptoTestData.firstSession
@@ -193,21 +199,12 @@ class E2eeSanityTests : InstrumentedTest {
                 }
             }
         }
-
-        otherAccounts.forEach {
-            testHelper.signOutAndClose(it)
-        }
-        newAccount.forEach { testHelper.signOutAndClose(it) }
-
-        cryptoTestData.cleanUp(testHelper)
     }
 
     @Test
-    fun testKeyGossipingIsEnabledByDefault() {
-        val testHelper = CommonTestHelper(context())
+    fun testKeyGossipingIsEnabledByDefault() = runSessionTest(context()) { testHelper ->
         val session = testHelper.createAccount("alice", SessionTestParams(true))
         Assert.assertTrue("Key gossiping should be enabled by default", session.cryptoService().isKeyGossipingEnabled())
-        testHelper.signOutAndClose(session)
     }
 
     /**
@@ -225,9 +222,7 @@ class E2eeSanityTests : InstrumentedTest {
      * 9. Check that new session can decrypt
      */
     @Test
-    fun testBasicBackupImport() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun testBasicBackupImport() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
 
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
         val aliceSession = cryptoTestData.firstSession
@@ -339,8 +334,6 @@ class E2eeSanityTests : InstrumentedTest {
 
         // ensure bob can now decrypt
         cryptoTestHelper.ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText)
-
-        testHelper.signOutAndClose(newBobSession)
     }
 
     /**
@@ -348,9 +341,7 @@ class E2eeSanityTests : InstrumentedTest {
      * get them from an older one.
      */
     @Test
-    fun testSimpleGossip() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun testSimpleGossip() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
 
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
         val aliceSession = cryptoTestData.firstSession
@@ -444,18 +435,13 @@ class E2eeSanityTests : InstrumentedTest {
         }
 
         cryptoTestHelper.ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText)
-
-        cryptoTestData.cleanUp(testHelper)
-        testHelper.signOutAndClose(newBobSession)
     }
 
     /**
      * Test that if a better key is forwarded (lower index, it is then used)
      */
     @Test
-    fun testForwardBetterKey() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun testForwardBetterKey() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
 
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
         val aliceSession = cryptoTestData.firstSession
@@ -521,10 +507,8 @@ class E2eeSanityTests : InstrumentedTest {
 
         // Confirm we can decrypt one but not the other
         testHelper.runBlockingTest {
-            try {
+            mustFail(message = "Should not be able to decrypt event") {
                 newBobSession.cryptoService().decryptEvent(firstEventNewBobPov.root, "")
-                fail("Should not be able to decrypt event")
-            } catch (_: MXCryptoError) {
             }
         }
 
@@ -573,10 +557,6 @@ class E2eeSanityTests : InstrumentedTest {
                 canDecryptFirst && canDecryptSecond
             }
         }
-
-        testHelper.signOutAndClose(aliceSession)
-        testHelper.signOutAndClose(bobSessionWithBetterKey)
-        testHelper.signOutAndClose(newBobSession)
     }
 
     private fun sendMessageInRoom(testHelper: CommonTestHelper, aliceRoomPOV: Room, text: String): String? {
@@ -607,9 +587,7 @@ class E2eeSanityTests : InstrumentedTest {
      * 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)
+    fun testASelfInteractiveVerificationAndGossip() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
 
         val aliceSession = testHelper.createAccount("alice", SessionTestParams(true))
         cryptoTestHelper.bootstrapSecurity(aliceSession)
@@ -648,7 +626,7 @@ class E2eeSanityTests : InstrumentedTest {
                         // we can release this latch?
                         oldCompleteLatch.countDown()
                     }
-                    else                                                -> Unit
+                    else -> Unit
                 }
             }
         })
@@ -675,17 +653,17 @@ class E2eeSanityTests : InstrumentedTest {
                     IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> {
                         // no need to accept as there was a request first it will auto accept
                     }
-                    IncomingSasVerificationTransaction.UxState.SHOW_SAS    -> {
+                    IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
                         if (matchOnce) {
                             sasTx.userHasVerifiedShortCode()
                             newCode = sasTx.getDecimalCodeRepresentation()
                             matchOnce = false
                         }
                     }
-                    IncomingSasVerificationTransaction.UxState.VERIFIED    -> {
+                    IncomingSasVerificationTransaction.UxState.VERIFIED -> {
                         newCompleteLatch.countDown()
                     }
-                    else                                                   -> Unit
+                    else -> Unit
                 }
             }
         })
@@ -748,9 +726,6 @@ class E2eeSanityTests : InstrumentedTest {
                 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) {
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 c2d8f4fb35f30c99457c8b81c2298d1a29b90763..bddb31fc92679510d6f3dda5d3dcfa6d3ab1e7d8 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
@@ -21,6 +21,7 @@ import org.junit.Assert.assertEquals
 import org.junit.Assert.assertTrue
 import org.junit.Assert.fail
 import org.junit.FixMethodOrder
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -30,6 +31,7 @@ import org.junit.runners.MethodSorters
  */
 @RunWith(AndroidJUnit4::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Ignore
 class ExportEncryptionTest {
 
     @Test
@@ -83,7 +85,8 @@ class ExportEncryptionTest {
     @Test
     fun checkExportDecrypt1() {
         val password = "password"
-        val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" + "cissyYBxjsfsAndErh065A8=\n-----END MEGOLM SESSION DATA-----"
+        val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" +
+                "cissyYBxjsfsAndErh065A8=\n-----END MEGOLM SESSION DATA-----"
         val expectedString = "plain"
 
         var decodedString: String? = null
@@ -103,7 +106,8 @@ class ExportEncryptionTest {
     @Test
     fun checkExportDecrypt2() {
         val password = "betterpassword"
-        val input = "-----BEGIN MEGOLM SESSION DATA-----\nAW1vcmVzYWx0bW9yZXNhbHT//////////wAAAAAAAAAAAAAD6KyBpe1Niv5M5NPm4ZATsJo5nghk\n" + "KYu63a0YQ5DRhUWEKk7CcMkrKnAUiZny\n-----END MEGOLM SESSION DATA-----"
+        val input = "-----BEGIN MEGOLM SESSION DATA-----\nAW1vcmVzYWx0bW9yZXNhbHT//////////wAAAAAAAAAAAAAD6KyBpe1Niv5M5NPm4ZATsJo5nghk\n" +
+                "KYu63a0YQ5DRhUWEKk7CcMkrKnAUiZny\n-----END MEGOLM SESSION DATA-----"
         val expectedString = "Hello, World"
 
         var decodedString: String? = null
@@ -123,7 +127,8 @@ class ExportEncryptionTest {
     @Test
     fun checkExportDecrypt3() {
         val password = "SWORDFISH"
-        val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXllc3NhbHR5Z29vZG5lc3P//////////wAAAAAAAAAAAAAD6OIW+Je7gwvjd4kYrb+49gKCfExw\n" + "MgJBMD4mrhLkmgAngwR1pHjbWXaoGybtiAYr0moQ93GrBQsCzPbvl82rZhaXO3iH5uHo/RCEpOqp\nPgg29363BGR+/Ripq/VCLKGNbw==\n-----END MEGOLM SESSION DATA-----"
+        val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXllc3NhbHR5Z29vZG5lc3P//////////wAAAAAAAAAAAAAD6OIW+Je7gwvjd4kYrb+49gKCfExw\n" +
+                "MgJBMD4mrhLkmgAngwR1pHjbWXaoGybtiAYr0moQ93GrBQsCzPbvl82rZhaXO3iH5uHo/RCEpOqp\nPgg29363BGR+/Ripq/VCLKGNbw==\n-----END MEGOLM SESSION DATA-----"
         val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically"
 
         var decodedString: String? = null
@@ -202,7 +207,8 @@ class ExportEncryptionTest {
 
     @Test
     fun checkExportEncrypt4() {
-        val password = "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword"
+        val password = "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" +
+                "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword"
         val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically"
         var decodedString: String? = null
 
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 93aa78a3050a8cb6e48f5ca288d2d60626fade8c..e37ae5be86ffb8a2354a17aeb78244093c8f1d29 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
@@ -30,18 +30,14 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventCon
 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.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
 
 @RunWith(AndroidJUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
 class PreShareKeysTest : InstrumentedTest {
 
-    private val testHelper = CommonTestHelper(context())
-    private val cryptoTestHelper = CryptoTestHelper(testHelper)
-
     @Test
-    fun ensure_outbound_session_happy_path() {
+    fun ensure_outbound_session_happy_path() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
         val e2eRoomID = testData.roomId
         val aliceSession = testData.firstSession
@@ -94,7 +90,5 @@ class PreShareKeysTest : InstrumentedTest {
                 bobSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEvent.eventId)?.root?.getClearType() == EventType.MESSAGE
             }
         }
-
-        testData.cleanUp(testHelper)
     }
 }
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 0f3a4b4181923e7c032ef4dc96b076f2933e1bd2..e8a474a54a5d9cd60a9eef8e2be89194571768d1 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
@@ -21,6 +21,7 @@ import org.amshove.kluent.shouldBe
 import org.junit.Assert
 import org.junit.Before
 import org.junit.FixMethodOrder
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -38,8 +39,7 @@ import org.matrix.android.sdk.api.session.getRoom
 import org.matrix.android.sdk.api.session.room.timeline.Timeline
 import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
-import org.matrix.android.sdk.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
 import org.matrix.android.sdk.common.TestConstants
 import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
 import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
@@ -60,11 +60,10 @@ import kotlin.coroutines.resume
  */
 @RunWith(AndroidJUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
+@Ignore
 class UnwedgingTest : InstrumentedTest {
 
     private lateinit var messagesReceivedByBob: List<TimelineEvent>
-    private val testHelper = CommonTestHelper(context())
-    private val cryptoTestHelper = CryptoTestHelper(testHelper)
 
     @Before
     fun init() {
@@ -85,7 +84,7 @@ class UnwedgingTest : InstrumentedTest {
      * -> This is automatically fixed after SDKs restarted the olm session
      */
     @Test
-    fun testUnwedging() {
+    fun testUnwedging() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
         val aliceSession = cryptoTestData.firstSession
@@ -240,8 +239,6 @@ class UnwedgingTest : InstrumentedTest {
         }
 
         bobTimeline.dispose()
-
-        cryptoTestData.cleanUp(testHelper)
     }
 
     private fun createEventListener(latch: CountDownLatch, expectedNumberOfMessages: Int): Timeline.Listener {
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 a37626dc20b9bd7bc825def322e6e1287625fbb3..8cb38ddc8749d0bb6729374f8c7526718cae3749 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
@@ -38,8 +38,8 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.isCrossSignedVerif
 import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified
 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.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
 import org.matrix.android.sdk.common.SessionTestParams
 import org.matrix.android.sdk.common.TestConstants
 import kotlin.coroutines.Continuation
@@ -48,13 +48,11 @@ import kotlin.coroutines.resume
 @RunWith(AndroidJUnit4::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @LargeTest
+@Ignore
 class XSigningTest : InstrumentedTest {
 
-    private val testHelper = CommonTestHelper(context())
-    private val cryptoTestHelper = CryptoTestHelper(testHelper)
-
     @Test
-    fun test_InitializeAndStoreKeys() {
+    fun test_InitializeAndStoreKeys() = runSessionTest(context()) { testHelper ->
         val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
 
         testHelper.doSync<Unit> {
@@ -88,7 +86,7 @@ class XSigningTest : InstrumentedTest {
     }
 
     @Test
-    fun test_CrossSigningCheckBobSeesTheKeys() {
+    fun test_CrossSigningCheckBobSeesTheKeys() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
         val aliceSession = cryptoTestData.firstSession
@@ -138,13 +136,10 @@ class XSigningTest : InstrumentedTest {
         )
 
         assertFalse("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV.isTrusted())
-
-        cryptoTestData.cleanUp(testHelper)
     }
 
     @Test
-    @Ignore("This test will be ignored until it is fixed")
-    fun test_CrossSigningTestAliceTrustBobNewDevice() {
+    fun test_CrossSigningTestAliceTrustBobNewDevice() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
         val aliceSession = cryptoTestData.firstSession
@@ -218,9 +213,5 @@ class XSigningTest : InstrumentedTest {
 
         val result = aliceSession.cryptoService().crossSigningService().checkDeviceTrust(bobUserId, bobSecondDeviceId, null)
         assertTrue("Bob second device should be trusted from alice POV", result.isCrossSignedVerified())
-
-        testHelper.signOutAndClose(aliceSession)
-        testHelper.signOutAndClose(bobSession)
-        testHelper.signOutAndClose(bobSession2)
     }
 }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt
index 85b6c21df37ea2744e84c86b29cbe9a8c89f036d..5f26fda94618019f119284305fa27a2360fbf50a 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt
@@ -35,6 +35,7 @@ import org.matrix.android.sdk.api.session.room.timeline.Timeline
 import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
 import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
 import org.matrix.android.sdk.common.CryptoTestHelper
 import java.util.concurrent.CountDownLatch
 
@@ -42,35 +43,36 @@ import java.util.concurrent.CountDownLatch
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 class EncryptionTest : InstrumentedTest {
 
-    private val testHelper = CommonTestHelper(context())
-    private val cryptoTestHelper = CryptoTestHelper(testHelper)
-
     @Test
     fun test_EncryptionEvent() {
-        performTest(roomShouldBeEncrypted = false) { room ->
-            // Send an encryption Event as an Event (and not as a state event)
-            room.sendService().sendEvent(
-                    eventType = EventType.STATE_ROOM_ENCRYPTION,
-                    content = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent()
-            )
+        runCryptoTest(context()) { cryptoTestHelper, testHelper ->
+            performTest(cryptoTestHelper, testHelper, roomShouldBeEncrypted = false) { room ->
+                // Send an encryption Event as an Event (and not as a state event)
+                room.sendService().sendEvent(
+                        eventType = EventType.STATE_ROOM_ENCRYPTION,
+                        content = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent()
+                )
+            }
         }
     }
 
     @Test
     fun test_EncryptionStateEvent() {
-        performTest(roomShouldBeEncrypted = true) { room ->
-            runBlocking {
-                // Send an encryption Event as a State Event
-                room.stateService().sendStateEvent(
-                        eventType = EventType.STATE_ROOM_ENCRYPTION,
-                        stateKey = "",
-                        body = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent()
-                )
+        runCryptoTest(context()) { cryptoTestHelper, testHelper ->
+            performTest(cryptoTestHelper, testHelper, roomShouldBeEncrypted = true) { room ->
+                runBlocking {
+                    // Send an encryption Event as a State Event
+                    room.stateService().sendStateEvent(
+                            eventType = EventType.STATE_ROOM_ENCRYPTION,
+                            stateKey = "",
+                            body = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent()
+                    )
+                }
             }
         }
     }
 
-    private fun performTest(roomShouldBeEncrypted: Boolean, action: (Room) -> Unit) {
+    private fun performTest(cryptoTestHelper: CryptoTestHelper, testHelper: CommonTestHelper, roomShouldBeEncrypted: Boolean, action: (Room) -> Unit) {
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(encryptedRoom = false)
 
         val aliceSession = cryptoTestData.firstSession
@@ -109,6 +111,5 @@ class EncryptionTest : InstrumentedTest {
             room.roomCryptoService().isEncrypted() shouldBe roomShouldBeEncrypted
             it.countDown()
         }
-        cryptoTestData.cleanUp(testHelper)
     }
 }
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 2e4fd62822ba37ca2c43ba3cc9c17497e2f18817..7bb53e139c3bd5d63206c844f0fa57aeb51755a2 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
@@ -21,11 +21,12 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 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.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -41,20 +42,22 @@ 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.timeline.getLastMessageContent
-import org.matrix.android.sdk.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
+import org.matrix.android.sdk.common.RetryTestRule
 import org.matrix.android.sdk.common.SessionTestParams
 import org.matrix.android.sdk.common.TestConstants
+import org.matrix.android.sdk.mustFail
 
 @RunWith(AndroidJUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
 @LargeTest
+@Ignore
 class KeyShareTests : InstrumentedTest {
 
+    @get:Rule val rule = RetryTestRule(3)
+
     @Test
-    fun test_DoNotSelfShareIfNotTrusted() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    fun test_DoNotSelfShareIfNotTrusted() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
 
         val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
         Log.v("TEST", "=======> AliceSession 1 is ${aliceSession.sessionParams.deviceId}")
@@ -91,12 +94,10 @@ class KeyShareTests : InstrumentedTest {
         assertNotNull(receivedEvent)
         assert(receivedEvent!!.isEncrypted())
 
-        try {
-            commonTestHelper.runBlockingTest {
+        commonTestHelper.runBlockingTest {
+            mustFail {
                 aliceSession2.cryptoService().decryptEvent(receivedEvent.root, "foo")
             }
-            fail("should fail")
-        } catch (failure: Throwable) {
         }
 
         val outgoingRequestsBefore = aliceSession2.cryptoService().getOutgoingRoomKeyRequests()
@@ -164,12 +165,10 @@ class KeyShareTests : InstrumentedTest {
             }
         }
 
-        try {
-            commonTestHelper.runBlockingTest {
+        commonTestHelper.runBlockingTest {
+            mustFail {
                 aliceSession2.cryptoService().decryptEvent(receivedEvent.root, "foo")
             }
-            fail("should fail")
-        } catch (failure: Throwable) {
         }
 
         // Mark the device as trusted
@@ -194,9 +193,7 @@ class KeyShareTests : InstrumentedTest {
      * if the key was originally shared with him
      */
     @Test
-    fun test_reShareIfWasIntendedToBeShared() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    fun test_reShareIfWasIntendedToBeShared() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
 
         val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
         val aliceSession = testData.firstSession
@@ -227,9 +224,7 @@ class KeyShareTests : InstrumentedTest {
      * if the key was originally shared with him
      */
     @Test
-    fun test_reShareToUnverifiedIfWasIntendedToBeShared() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    fun test_reShareToUnverifiedIfWasIntendedToBeShared() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
 
         val testData = cryptoTestHelper.doE2ETestWithAliceInARoom(true)
         val aliceSession = testData.firstSession
@@ -266,9 +261,7 @@ class KeyShareTests : InstrumentedTest {
      * Tests that keys reshared with own verified session are done from the earliest known index
      */
     @Test
-    fun test_reShareFromTheEarliestKnownIndexWithOwnVerifiedSession() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    fun test_reShareFromTheEarliestKnownIndexWithOwnVerifiedSession() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
 
         val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
         val aliceSession = testData.firstSession
@@ -388,10 +381,7 @@ class KeyShareTests : InstrumentedTest {
      * Tests that we don't cancel a request to early on first forward if the index is not good enough
      */
     @Test
-    fun test_dontCancelToEarly() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
-
+    fun test_dontCancelToEarly() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
         val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
         val aliceSession = testData.firstSession
         val bobSession = testData.secondSession!!
@@ -434,7 +424,7 @@ class KeyShareTests : InstrumentedTest {
 
         // /!\ Stop initial alice session syncing so that it can't reply
         aliceSession.cryptoService().enableKeyGossiping(false)
-        aliceSession.stopSync()
+        aliceSession.syncService().stopSync()
 
         // Let's now try to request
         aliceNewSession.cryptoService().reRequestRoomKeyForEvent(sentEvents.first().root)
@@ -442,7 +432,7 @@ class KeyShareTests : InstrumentedTest {
         // 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 ?: "?" }}")
+                //  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
@@ -457,7 +447,7 @@ class KeyShareTests : InstrumentedTest {
 
         // let's wake up alice
         aliceSession.cryptoService().enableKeyGossiping(true)
-        aliceSession.startSync(true)
+        aliceSession.syncService().startSync(true)
 
         // We should now get a reply from first session
         commonTestHelper.waitWithLatch { latch ->
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 cb31a2232fb672c7e54fecbfff1a5c5c91e90d9e..ae420a09b38e59414d3cc90dd223a62369cafc22 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,6 +21,8 @@ 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.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -35,21 +37,23 @@ 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.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
 import org.matrix.android.sdk.common.MockOkHttpInterceptor
+import org.matrix.android.sdk.common.RetryTestRule
 import org.matrix.android.sdk.common.SessionTestParams
 import org.matrix.android.sdk.common.TestConstants
+import org.matrix.android.sdk.mustFail
 
 @RunWith(AndroidJUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
 @LargeTest
+@Ignore
 class WithHeldTests : InstrumentedTest {
 
+    @get:Rule val rule = RetryTestRule(3)
+
     @Test
-    fun test_WithHeldUnverifiedReason() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun test_WithHeldUnverifiedReason() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
 
         // =============================
         // ARRANGE
@@ -92,17 +96,19 @@ class WithHeldTests : InstrumentedTest {
         // =============================
 
         // Bob should not be able to decrypt because the keys is withheld
-        try {
-            // .. might need to wait a bit for stability?
-            testHelper.runBlockingTest {
+        // .. might need to wait a bit for stability?
+        testHelper.runBlockingTest {
+            mustFail(
+                    message = "This session should not be able to decrypt",
+                    failureBlock = { failure ->
+                        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)
+                    }
+            ) {
                 bobUnverifiedSession.cryptoService().decryptEvent(eventBobPOV.root, "")
             }
-            Assert.fail("This session should not be able to decrypt")
-        } catch (failure: Throwable) {
-            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.UNAUTHORISED.value, technicalMessage)
         }
 
         // Let's see if the reply we got from bob first session is unverified
@@ -133,28 +139,23 @@ class WithHeldTests : InstrumentedTest {
         }
 
         // Previous message should still be undecryptable (partially withheld session)
-        try {
-            // .. might need to wait a bit for stability?
-            testHelper.runBlockingTest {
+        // .. might need to wait a bit for stability?
+        testHelper.runBlockingTest {
+            mustFail(
+                    message = "This session should not be able to decrypt",
+                    failureBlock = { failure ->
+                        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)
+                    }) {
                 bobUnverifiedSession.cryptoService().decryptEvent(eventBobPOV.root, "")
             }
-            Assert.fail("This session should not be able to decrypt")
-        } catch (failure: Throwable) {
-            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.UNAUTHORISED.value, technicalMessage)
         }
-
-        testHelper.signOutAndClose(aliceSession)
-        testHelper.signOutAndClose(bobSession)
-        testHelper.signOutAndClose(bobUnverifiedSession)
     }
 
     @Test
-    fun test_WithHeldNoOlm() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun test_WithHeldNoOlm() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
 
         val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
         val aliceSession = testData.firstSession
@@ -186,17 +187,18 @@ class WithHeldTests : InstrumentedTest {
 
         // Previous message should still be undecryptable (partially withheld session)
         val eventBobPOV = bobSession.getRoom(testData.roomId)?.getTimelineEvent(eventId)
-        try {
-            // .. might need to wait a bit for stability?
-            testHelper.runBlockingTest {
+        // .. might need to wait a bit for stability?
+        testHelper.runBlockingTest {
+            mustFail(
+                    message = "This session should not be able to decrypt",
+                    failureBlock = { failure ->
+                        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.NO_OLM.value, technicalMessage)
+                    }) {
                 bobSession.cryptoService().decryptEvent(eventBobPOV!!.root, "")
             }
-            Assert.fail("This session should not be able to decrypt")
-        } catch (failure: Throwable) {
-            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.NO_OLM.value, technicalMessage)
         }
 
         // Ensure that alice has marked the session to be shared with bob
@@ -230,14 +232,10 @@ class WithHeldTests : InstrumentedTest {
         Assert.assertEquals("Alice should have marked bob's device for this session", 1, chainIndex2)
 
         aliceInterceptor.clearRules()
-        testData.cleanUp(testHelper)
-        testHelper.signOutAndClose(bobSecondSession)
     }
 
     @Test
-    fun test_WithHeldKeyRequest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun test_WithHeldKeyRequest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
 
         val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
         val aliceSession = testData.firstSession
@@ -284,8 +282,5 @@ 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/KeysBackupTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt
index 9136272b1ee7fc396c7a162e797efe1c75a5d72d..fb498e0de5dfde0e47a872738d7ea5fe32b7b111 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,6 +24,8 @@ 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.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -43,8 +45,9 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreation
 import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
 import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
 import org.matrix.android.sdk.api.session.getRoom
-import org.matrix.android.sdk.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
+import org.matrix.android.sdk.common.RetryTestRule
 import org.matrix.android.sdk.common.TestConstants
 import org.matrix.android.sdk.common.TestMatrixCallback
 import java.util.Collections
@@ -53,17 +56,18 @@ import java.util.concurrent.CountDownLatch
 @RunWith(AndroidJUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
 @LargeTest
+@Ignore
 class KeysBackupTest : InstrumentedTest {
 
+    @get:Rule val rule = RetryTestRule(3)
+
     /**
      * - From doE2ETestWithAliceAndBobInARoomWithEncryptedMessages, we should have no backed up keys
      * - Check backup keys after having marked one as backed up
      * - Reset keys backup markers
      */
     @Test
-    fun roomKeysTest_testBackupStore_ok() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun roomKeysTest_testBackupStore_ok() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
 
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
 
@@ -102,8 +106,7 @@ class KeysBackupTest : InstrumentedTest {
      * Check that prepareKeysBackupVersionWithPassword returns valid data
      */
     @Test
-    fun prepareKeysBackupVersionTest() {
-        val testHelper = CommonTestHelper(context())
+    fun prepareKeysBackupVersionTest() = runSessionTest(context()) { testHelper ->
 
         val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
 
@@ -113,7 +116,7 @@ class KeysBackupTest : InstrumentedTest {
 
         val stateObserver = StateObserver(keysBackup)
 
-        assertFalse(keysBackup.isEnabled)
+        assertFalse(keysBackup.isEnabled())
 
         val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> {
             keysBackup.prepareKeysBackupVersion(null, null, it)
@@ -125,16 +128,13 @@ class KeysBackupTest : InstrumentedTest {
         assertNotNull(megolmBackupCreationInfo.recoveryKey)
 
         stateObserver.stopAndCheckStates(null)
-        testHelper.signOutAndClose(bobSession)
     }
 
     /**
      * Test creating a keys backup version and check that createKeysBackupVersion() returns valid data
      */
     @Test
-    fun createKeysBackupVersionTest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun createKeysBackupVersionTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
 
         val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
         cryptoTestHelper.initializeCrossSigning(bobSession)
@@ -143,13 +143,13 @@ class KeysBackupTest : InstrumentedTest {
 
         val stateObserver = StateObserver(keysBackup)
 
-        assertFalse(keysBackup.isEnabled)
+        assertFalse(keysBackup.isEnabled())
 
         val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> {
             keysBackup.prepareKeysBackupVersion(null, null, it)
         }
 
-        assertFalse(keysBackup.isEnabled)
+        assertFalse(keysBackup.isEnabled())
 
         // Create the version
         val version = testHelper.doSync<KeysVersion> {
@@ -157,7 +157,7 @@ class KeysBackupTest : InstrumentedTest {
         }
 
         // Backup must be enable now
-        assertTrue(keysBackup.isEnabled)
+        assertTrue(keysBackup.isEnabled())
 
         // Check that it's signed with MSK
         val versionResult = testHelper.doSync<KeysVersionResult?> {
@@ -193,7 +193,6 @@ class KeysBackupTest : InstrumentedTest {
                 }
 
         stateObserver.stopAndCheckStates(null)
-        testHelper.signOutAndClose(bobSession)
     }
 
     /**
@@ -201,9 +200,7 @@ class KeysBackupTest : InstrumentedTest {
      * - Check the backup completes
      */
     @Test
-    fun backupAfterCreateKeysBackupVersionTest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun backupAfterCreateKeysBackupVersionTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
@@ -238,16 +235,13 @@ class KeysBackupTest : InstrumentedTest {
                         KeysBackupState.ReadyToBackUp
                 )
         )
-        cryptoTestData.cleanUp(testHelper)
     }
 
     /**
      * Check that backupAllGroupSessions() returns valid data
      */
     @Test
-    fun backupAllGroupSessionsTest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun backupAllGroupSessionsTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
@@ -281,7 +275,6 @@ class KeysBackupTest : InstrumentedTest {
         assertEquals("All keys must have been marked as backed up", nbOfKeys, backedUpKeys)
 
         stateObserver.stopAndCheckStates(null)
-        cryptoTestData.cleanUp(testHelper)
     }
 
     /**
@@ -293,9 +286,7 @@ class KeysBackupTest : InstrumentedTest {
      * - Compare the decrypted megolm key with the original one
      */
     @Test
-    fun testEncryptAndDecryptKeysBackupData() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun testEncryptAndDecryptKeysBackupData() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages()
@@ -330,7 +321,6 @@ class KeysBackupTest : InstrumentedTest {
         keysBackupTestHelper.assertKeysEquals(session.exportKeys(), sessionData)
 
         stateObserver.stopAndCheckStates(null)
-        cryptoTestData.cleanUp(testHelper)
     }
 
     /**
@@ -340,9 +330,7 @@ class KeysBackupTest : InstrumentedTest {
      * - Restore must be successful
      */
     @Test
-    fun restoreKeysBackupTest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun restoreKeysBackupTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
@@ -428,9 +416,7 @@ class KeysBackupTest : InstrumentedTest {
      * - It must be trusted and must have with 2 signatures now
      */
     @Test
-    fun trustKeyBackupVersionTest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun trustKeyBackupVersionTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         // - Do an e2e backup to the homeserver with a recovery key
@@ -441,8 +427,8 @@ class KeysBackupTest : InstrumentedTest {
 
         // - The new device must see the previous backup as not trusted
         assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
-        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
-        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
+        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
+        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
 
         // - Trust the backup from the new device
         testHelper.doSync<Unit> {
@@ -458,7 +444,7 @@ class KeysBackupTest : InstrumentedTest {
 
         // - Backup must be enabled on the new device, on the same version
         assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version)
-        assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
+        assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
 
         // - Retrieve the last version from the server
         val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> {
@@ -477,7 +463,6 @@ class KeysBackupTest : InstrumentedTest {
         assertEquals(2, keysBackupVersionTrust.signatures.size)
 
         stateObserver.stopAndCheckStates(null)
-        testData.cleanUp(testHelper)
     }
 
     /**
@@ -491,9 +476,7 @@ class KeysBackupTest : InstrumentedTest {
      * - It must be trusted and must have with 2 signatures now
      */
     @Test
-    fun trustKeyBackupVersionWithRecoveryKeyTest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun trustKeyBackupVersionWithRecoveryKeyTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         // - Do an e2e backup to the homeserver with a recovery key
@@ -504,8 +487,8 @@ class KeysBackupTest : InstrumentedTest {
 
         // - The new device must see the previous backup as not trusted
         assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
-        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
-        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
+        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
+        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
 
         // - Trust the backup from the new device with the recovery key
         testHelper.doSync<Unit> {
@@ -521,7 +504,7 @@ class KeysBackupTest : InstrumentedTest {
 
         // - Backup must be enabled on the new device, on the same version
         assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version)
-        assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
+        assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
 
         // - Retrieve the last version from the server
         val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> {
@@ -540,7 +523,6 @@ class KeysBackupTest : InstrumentedTest {
         assertEquals(2, keysBackupVersionTrust.signatures.size)
 
         stateObserver.stopAndCheckStates(null)
-        testData.cleanUp(testHelper)
     }
 
     /**
@@ -552,9 +534,7 @@ class KeysBackupTest : InstrumentedTest {
      * - The backup must still be untrusted and disabled
      */
     @Test
-    fun trustKeyBackupVersionWithWrongRecoveryKeyTest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun trustKeyBackupVersionWithWrongRecoveryKeyTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         // - Do an e2e backup to the homeserver with a recovery key
@@ -565,8 +545,8 @@ class KeysBackupTest : InstrumentedTest {
 
         // - The new device must see the previous backup as not trusted
         assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
-        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
-        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
+        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
+        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
 
         // - Try to trust the backup from the new device with a wrong recovery key
         val latch = CountDownLatch(1)
@@ -579,11 +559,10 @@ class KeysBackupTest : InstrumentedTest {
 
         // - The new device must still see the previous backup as not trusted
         assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
-        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
-        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
+        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
+        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
 
         stateObserver.stopAndCheckStates(null)
-        testData.cleanUp(testHelper)
     }
 
     /**
@@ -597,9 +576,7 @@ class KeysBackupTest : InstrumentedTest {
      * - It must be trusted and must have with 2 signatures now
      */
     @Test
-    fun trustKeyBackupVersionWithPasswordTest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun trustKeyBackupVersionWithPasswordTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         val password = "Password"
@@ -612,8 +589,8 @@ class KeysBackupTest : InstrumentedTest {
 
         // - The new device must see the previous backup as not trusted
         assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
-        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
-        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
+        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
+        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
 
         // - Trust the backup from the new device with the password
         testHelper.doSync<Unit> {
@@ -629,7 +606,7 @@ class KeysBackupTest : InstrumentedTest {
 
         // - Backup must be enabled on the new device, on the same version
         assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version)
-        assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
+        assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
 
         // - Retrieve the last version from the server
         val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> {
@@ -648,7 +625,6 @@ class KeysBackupTest : InstrumentedTest {
         assertEquals(2, keysBackupVersionTrust.signatures.size)
 
         stateObserver.stopAndCheckStates(null)
-        testData.cleanUp(testHelper)
     }
 
     /**
@@ -660,9 +636,7 @@ class KeysBackupTest : InstrumentedTest {
      * - The backup must still be untrusted and disabled
      */
     @Test
-    fun trustKeyBackupVersionWithWrongPasswordTest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun trustKeyBackupVersionWithWrongPasswordTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         val password = "Password"
@@ -676,8 +650,8 @@ class KeysBackupTest : InstrumentedTest {
 
         // - The new device must see the previous backup as not trusted
         assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
-        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
-        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
+        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
+        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
 
         // - Try to trust the backup from the new device with a wrong password
         val latch = CountDownLatch(1)
@@ -690,11 +664,10 @@ class KeysBackupTest : InstrumentedTest {
 
         // - The new device must still see the previous backup as not trusted
         assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion)
-        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled)
-        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state)
+        assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled())
+        assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState())
 
         stateObserver.stopAndCheckStates(null)
-        testData.cleanUp(testHelper)
     }
 
     /**
@@ -704,9 +677,7 @@ class KeysBackupTest : InstrumentedTest {
      * - It must fail
      */
     @Test
-    fun restoreKeysBackupWithAWrongRecoveryKeyTest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun restoreKeysBackupWithAWrongRecoveryKeyTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
@@ -730,8 +701,6 @@ class KeysBackupTest : InstrumentedTest {
 
         // onSuccess may not have been called
         assertNull(importRoomKeysResult)
-
-        testData.cleanUp(testHelper)
     }
 
     /**
@@ -741,9 +710,7 @@ class KeysBackupTest : InstrumentedTest {
      * - Restore must be successful
      */
     @Test
-    fun testBackupWithPassword() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun testBackupWithPassword() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         val password = "password"
@@ -790,8 +757,6 @@ class KeysBackupTest : InstrumentedTest {
         assertEquals(100, (steps[104] as StepProgressListener.Step.ImportingKey).progress)
 
         keysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
-
-        testData.cleanUp(testHelper)
     }
 
     /**
@@ -801,9 +766,7 @@ class KeysBackupTest : InstrumentedTest {
      * - It must fail
      */
     @Test
-    fun restoreKeysBackupWithAWrongPasswordTest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun restoreKeysBackupWithAWrongPasswordTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         val password = "password"
@@ -830,8 +793,6 @@ class KeysBackupTest : InstrumentedTest {
 
         // onSuccess may not have been called
         assertNull(importRoomKeysResult)
-
-        testData.cleanUp(testHelper)
     }
 
     /**
@@ -841,9 +802,7 @@ class KeysBackupTest : InstrumentedTest {
      * - Restore must be successful
      */
     @Test
-    fun testUseRecoveryKeyToRestoreAPasswordBasedKeysBackup() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun testUseRecoveryKeyToRestoreAPasswordBasedKeysBackup() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         val password = "password"
@@ -863,8 +822,6 @@ class KeysBackupTest : InstrumentedTest {
         }
 
         keysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys)
-
-        testData.cleanUp(testHelper)
     }
 
     /**
@@ -874,9 +831,7 @@ class KeysBackupTest : InstrumentedTest {
      * - It must fail
      */
     @Test
-    fun testUsePasswordToRestoreARecoveryKeyBasedKeysBackup() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun testUsePasswordToRestoreARecoveryKeyBasedKeysBackup() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null)
@@ -900,8 +855,6 @@ class KeysBackupTest : InstrumentedTest {
 
         // onSuccess may not have been called
         assertNull(importRoomKeysResult)
-
-        testData.cleanUp(testHelper)
     }
 
     /**
@@ -909,9 +862,7 @@ class KeysBackupTest : InstrumentedTest {
      * - Check the returned KeysVersionResult is trusted
      */
     @Test
-    fun testIsKeysBackupTrusted() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun testIsKeysBackupTrusted() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         // - Create a backup version
@@ -945,7 +896,6 @@ class KeysBackupTest : InstrumentedTest {
         assertEquals(signature.device!!.deviceId, cryptoTestData.firstSession.sessionParams.deviceId)
 
         stateObserver.stopAndCheckStates(null)
-        cryptoTestData.cleanUp(testHelper)
     }
 
     /**
@@ -957,9 +907,7 @@ class KeysBackupTest : InstrumentedTest {
      * -> That must fail and her backup state must be WrongBackUpVersion
      */
     @Test
-    fun testBackupWhenAnotherBackupWasCreated() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun testBackupWhenAnotherBackupWasCreated() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         // - Create a backup version
@@ -969,7 +917,7 @@ class KeysBackupTest : InstrumentedTest {
 
         val stateObserver = StateObserver(keysBackup)
 
-        assertFalse(keysBackup.isEnabled)
+        assertFalse(keysBackup.isEnabled())
 
         // Wait for keys backup to be finished
         val latch0 = CountDownLatch(1)
@@ -993,7 +941,7 @@ class KeysBackupTest : InstrumentedTest {
         // - Make alice back up her keys to her homeserver
         keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
 
-        assertTrue(keysBackup.isEnabled)
+        assertTrue(keysBackup.isEnabled())
 
         testHelper.await(latch0)
 
@@ -1012,11 +960,10 @@ class KeysBackupTest : InstrumentedTest {
         testHelper.await(latch2)
 
         // -> That must fail and her backup state must be WrongBackUpVersion
-        assertEquals(KeysBackupState.WrongBackUpVersion, keysBackup.state)
-        assertFalse(keysBackup.isEnabled)
+        assertEquals(KeysBackupState.WrongBackUpVersion, keysBackup.getState())
+        assertFalse(keysBackup.isEnabled())
 
         stateObserver.stopAndCheckStates(null)
-        cryptoTestData.cleanUp(testHelper)
     }
 
     /**
@@ -1032,9 +979,7 @@ class KeysBackupTest : InstrumentedTest {
      * -> It must success
      */
     @Test
-    fun testBackupAfterVerifyingADevice() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun testBackupAfterVerifyingADevice() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         // - Create a backup version
@@ -1069,7 +1014,7 @@ 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)
+        assertFalse("Backup should not be enabled", keysBackup2.isEnabled())
 
         val stateObserver2 = StateObserver(keysBackup2)
 
@@ -1088,8 +1033,8 @@ class KeysBackupTest : InstrumentedTest {
         assertFalse(isSuccessful)
 
         // Backup state must be NotTrusted
-        assertEquals("Backup state must be NotTrusted", KeysBackupState.NotTrusted, keysBackup2.state)
-        assertFalse("Backup should not be enabled", keysBackup2.isEnabled)
+        assertEquals("Backup state must be NotTrusted", KeysBackupState.NotTrusted, keysBackup2.getState())
+        assertFalse("Backup should not be enabled", keysBackup2.isEnabled())
 
         // - Validate the old device from the new one
         aliceSession2.cryptoService().setDeviceVerification(
@@ -1103,7 +1048,7 @@ class KeysBackupTest : InstrumentedTest {
         keysBackup2.addListener(object : KeysBackupStateListener {
             override fun onStateChange(newState: KeysBackupState) {
                 // Check the backup completes
-                if (keysBackup2.state == KeysBackupState.ReadyToBackUp) {
+                if (keysBackup2.getState() == KeysBackupState.ReadyToBackUp) {
                     // Remove itself from the list of listeners
                     keysBackup2.removeListener(this)
 
@@ -1121,12 +1066,10 @@ class KeysBackupTest : InstrumentedTest {
         }
 
         // -> It must success
-        assertTrue(aliceSession2.cryptoService().keysBackupService().isEnabled)
+        assertTrue(aliceSession2.cryptoService().keysBackupService().isEnabled())
 
         stateObserver.stopAndCheckStates(null)
         stateObserver2.stopAndCheckStates(null)
-        testHelper.signOutAndClose(aliceSession2)
-        cryptoTestData.cleanUp(testHelper)
     }
 
     /**
@@ -1134,9 +1077,7 @@ class KeysBackupTest : InstrumentedTest {
      * - Delete the backup
      */
     @Test
-    fun deleteKeysBackupTest() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun deleteKeysBackupTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
 
         // - Create a backup version
@@ -1146,19 +1087,18 @@ class KeysBackupTest : InstrumentedTest {
 
         val stateObserver = StateObserver(keysBackup)
 
-        assertFalse(keysBackup.isEnabled)
+        assertFalse(keysBackup.isEnabled())
 
         val keyBackupCreationInfo = keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup)
 
-        assertTrue(keysBackup.isEnabled)
+        assertTrue(keysBackup.isEnabled())
 
         // Delete the backup
         testHelper.doSync<Unit> { keysBackup.deleteBackup(keyBackupCreationInfo.version, it) }
 
         // Backup is now disabled
-        assertFalse(keysBackup.isEnabled)
+        assertFalse(keysBackup.isEnabled())
 
         stateObserver.stopAndCheckStates(null)
-        cryptoTestData.cleanUp(testHelper)
     }
 }
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 2220536e28c7579d8cf5af4367b425e2deb494a4..38f94c51039cb9a57c5af236c6f56233259b187a 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
@@ -33,7 +33,8 @@ import java.util.concurrent.CountDownLatch
 
 internal class KeysBackupTestHelper(
         private val testHelper: CommonTestHelper,
-        private val cryptoTestHelper: CryptoTestHelper) {
+        private val cryptoTestHelper: CryptoTestHelper
+) {
 
     fun waitForKeybackUpBatching() {
         Thread.sleep(400)
@@ -96,8 +97,10 @@ internal class KeysBackupTestHelper(
         )
     }
 
-    fun prepareAndCreateKeysBackupData(keysBackup: KeysBackupService,
-                                       password: String? = null): PrepareKeysBackupDataResult {
+    fun prepareAndCreateKeysBackupData(
+            keysBackup: KeysBackupService,
+            password: String? = null
+    ): PrepareKeysBackupDataResult {
         val stateObserver = StateObserver(keysBackup)
 
         val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> {
@@ -106,7 +109,7 @@ internal class KeysBackupTestHelper(
 
         Assert.assertNotNull(megolmBackupCreationInfo)
 
-        Assert.assertFalse("Key backup should not be enabled before creation", keysBackup.isEnabled)
+        Assert.assertFalse("Key backup should not be enabled before creation", keysBackup.isEnabled())
 
         // Create the version
         val keysVersion = testHelper.doSync<KeysVersion> {
@@ -116,7 +119,7 @@ internal class KeysBackupTestHelper(
         Assert.assertNotNull("Key backup version should not be null", keysVersion.version)
 
         // Backup must be enable now
-        Assert.assertTrue(keysBackup.isEnabled)
+        Assert.assertTrue(keysBackup.isEnabled())
 
         stateObserver.stopAndCheckStates(null)
         return PrepareKeysBackupDataResult(megolmBackupCreationInfo, keysVersion.version)
@@ -128,7 +131,7 @@ internal class KeysBackupTestHelper(
      */
     fun waitForKeysBackupToBeInState(session: Session, state: KeysBackupState) {
         // If already in the wanted state, return
-        if (session.cryptoService().keysBackupService().state == state) {
+        if (session.cryptoService().keysBackupService().getState() == state) {
             return
         }
 
@@ -169,9 +172,11 @@ internal class KeysBackupTestHelper(
      * - The new device must have the same count of megolm keys
      * - Alice must have the same keys on both devices
      */
-    fun checkRestoreSuccess(testData: KeysBackupScenarioData,
-                            total: Int,
-                            imported: Int) {
+    fun checkRestoreSuccess(
+            testData: KeysBackupScenarioData,
+            total: Int,
+            imported: Int
+    ) {
         // - Imported keys number must be correct
         Assert.assertEquals(testData.aliceKeys.size, total)
         Assert.assertEquals(total, imported)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/PrepareKeysBackupDataResult.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/PrepareKeysBackupDataResult.kt
index 31bd3c9cce5d8670f3db0ad745034a9e2493c263..9ee10eddcfc3bf3c21d46f79b571e85b737492d3 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/PrepareKeysBackupDataResult.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/PrepareKeysBackupDataResult.kt
@@ -18,5 +18,7 @@ package org.matrix.android.sdk.internal.crypto.keysbackup
 
 import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
 
-data class PrepareKeysBackupDataResult(val megolmBackupCreationInfo: MegolmBackupCreationInfo,
-                                       val version: String)
+data class PrepareKeysBackupDataResult(
+        val megolmBackupCreationInfo: MegolmBackupCreationInfo,
+        val version: String
+)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/StateObserver.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/StateObserver.kt
index 80e54d82ec76d115861c4ca5bdfa173281e85d29..6c977745479210a7b9c3f7f72965af86ea8da65c 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/StateObserver.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/StateObserver.kt
@@ -27,9 +27,11 @@ import java.util.concurrent.CountDownLatch
  * This class observe the state change of a KeysBackup object and provide a method to check the several state change
  * It checks all state transitions and detected forbidden transition
  */
-internal class StateObserver(private val keysBackup: KeysBackupService,
-                             private val latch: CountDownLatch? = null,
-                             private val expectedStateChange: Int = -1) : KeysBackupStateListener {
+internal class StateObserver(
+        private val keysBackup: KeysBackupService,
+        private val latch: CountDownLatch? = null,
+        private val expectedStateChange: Int = -1
+) : KeysBackupStateListener {
 
     private val allowedStateTransitions = listOf(
             KeysBackupState.BackingUp to KeysBackupState.ReadyToBackUp,
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/replayattack/ReplayAttackTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/replayattack/ReplayAttackTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..53cf802b91e9978a09906cff4fbc7e757db675fd
--- /dev/null
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/replayattack/ReplayAttackTest.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.replayattack
+
+import androidx.test.filters.LargeTest
+import org.amshove.kluent.internal.assertFailsWith
+import org.junit.Assert
+import org.junit.Assert.assertEquals
+import org.junit.Assert.fail
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.runners.MethodSorters
+import org.matrix.android.sdk.InstrumentedTest
+import org.matrix.android.sdk.api.session.crypto.MXCryptoError
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
+
+@RunWith(JUnit4::class)
+@FixMethodOrder(MethodSorters.JVM)
+@LargeTest
+class ReplayAttackTest : InstrumentedTest {
+
+    @Test
+    fun replayAttackAlreadyDecryptedEventTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
+        val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
+
+        val e2eRoomID = cryptoTestData.roomId
+
+        // Alice
+        val aliceSession = cryptoTestData.firstSession
+        val aliceRoomPOV = aliceSession.roomService().getRoom(e2eRoomID)!!
+
+        // Bob
+        val bobSession = cryptoTestData.secondSession
+        val bobRoomPOV = bobSession!!.roomService().getRoom(e2eRoomID)!!
+        assertEquals(bobRoomPOV.roomSummary()?.joinedMembersCount, 2)
+
+        // Alice will send a message
+        val sentEvents = testHelper.sendTextMessage(aliceRoomPOV, "Hello I will be decrypted twice", 1)
+        assertEquals(1, sentEvents.size)
+
+        val fakeEventId = sentEvents[0].eventId + "_fake"
+        val fakeEventWithTheSameIndex =
+                sentEvents[0].copy(eventId = fakeEventId, root = sentEvents[0].root.copy(eventId = fakeEventId))
+
+        testHelper.runBlockingTest {
+            // Lets assume we are from the main timelineId
+            val timelineId = "timelineId"
+            // Lets decrypt the original event
+            aliceSession.cryptoService().decryptEvent(sentEvents[0].root, timelineId)
+            // Lets decrypt the fake event that will have the same message index
+            val exception = assertFailsWith<MXCryptoError.Base> {
+                // An exception should be thrown while the same index would have been used for the previous decryption
+                aliceSession.cryptoService().decryptEvent(fakeEventWithTheSameIndex.root, timelineId)
+            }
+            assertEquals(MXCryptoError.ErrorType.DUPLICATED_MESSAGE_INDEX, exception.errorType)
+        }
+        cryptoTestData.cleanUp(testHelper)
+    }
+
+    @Test
+    fun replayAttackSameEventTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
+        val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
+
+        val e2eRoomID = cryptoTestData.roomId
+
+        // Alice
+        val aliceSession = cryptoTestData.firstSession
+        val aliceRoomPOV = aliceSession.roomService().getRoom(e2eRoomID)!!
+
+        // Bob
+        val bobSession = cryptoTestData.secondSession
+        val bobRoomPOV = bobSession!!.roomService().getRoom(e2eRoomID)!!
+        assertEquals(bobRoomPOV.roomSummary()?.joinedMembersCount, 2)
+
+        // Alice will send a message
+        val sentEvents = testHelper.sendTextMessage(aliceRoomPOV, "Hello I will be decrypted twice", 1)
+        Assert.assertTrue("Message should be sent", sentEvents.size == 1)
+        assertEquals(sentEvents.size, 1)
+
+        testHelper.runBlockingTest {
+            // Lets assume we are from the main timelineId
+            val timelineId = "timelineId"
+            // Lets decrypt the original event
+            aliceSession.cryptoService().decryptEvent(sentEvents[0].root, timelineId)
+            try {
+                // Lets try to decrypt the same event
+                aliceSession.cryptoService().decryptEvent(sentEvents[0].root, timelineId)
+            } catch (ex: Throwable) {
+                fail("Shouldn't throw a decryption error for same event")
+            }
+        }
+    }
+}
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 c758050fc9548f4a1fb926462e7ffb2e6c211279..c8be6aae74ec8a6bcb24a9a5ce4e36e238c591d7 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
@@ -31,15 +31,16 @@ import org.matrix.android.sdk.api.crypto.SSSS_ALGORITHM_AES_HMAC_SHA2
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
 import org.matrix.android.sdk.api.session.securestorage.EncryptedSecretContent
+import org.matrix.android.sdk.api.session.securestorage.KeyRef
 import org.matrix.android.sdk.api.session.securestorage.KeySigner
 import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
 import org.matrix.android.sdk.api.session.securestorage.SecretStorageKeyContent
 import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageError
-import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService
 import org.matrix.android.sdk.api.session.securestorage.SsssKeyCreationInfo
 import org.matrix.android.sdk.api.util.Optional
 import org.matrix.android.sdk.api.util.toBase64NoPadding
 import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
 import org.matrix.android.sdk.common.SessionTestParams
 import org.matrix.android.sdk.common.TestConstants
 import org.matrix.android.sdk.internal.crypto.secrets.DefaultSharedSecretStorageService
@@ -55,8 +56,7 @@ class QuadSTests : InstrumentedTest {
     }
 
     @Test
-    fun test_Generate4SKey() {
-        val testHelper = CommonTestHelper(context())
+    fun test_Generate4SKey() = runSessionTest(context()) { testHelper ->
 
         val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
 
@@ -108,12 +108,11 @@ class QuadSTests : InstrumentedTest {
     }
 
     @Test
-    fun test_StoreSecret() {
-        val testHelper = CommonTestHelper(context())
+    fun test_StoreSecret() = runSessionTest(context()) { testHelper ->
 
         val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
         val keyId = "My.Key"
-        val info = generatedSecret(aliceSession, keyId, true)
+        val info = generatedSecret(testHelper, aliceSession, keyId, true)
 
         val keySpec = RawBytesKeySpec.fromRecoveryKey(info.recoveryKey)
 
@@ -123,11 +122,11 @@ class QuadSTests : InstrumentedTest {
             aliceSession.sharedSecretStorageService().storeSecret(
                     "secret.of.life",
                     clearSecret,
-                    listOf(SharedSecretStorageService.KeyRef(null, keySpec)) // default key
+                    listOf(KeyRef(null, keySpec)) // default key
             )
         }
 
-        val secretAccountData = assertAccountData(aliceSession, "secret.of.life")
+        val secretAccountData = assertAccountData(testHelper, aliceSession, "secret.of.life")
 
         val encryptedContent = secretAccountData.content["encrypted"] as? Map<*, *>
         assertNotNull("Element should be encrypted", encryptedContent)
@@ -149,12 +148,10 @@ class QuadSTests : InstrumentedTest {
         }
 
         assertEquals("Secret mismatch", clearSecret, decryptedSecret)
-        testHelper.signOutAndClose(aliceSession)
     }
 
     @Test
-    fun test_SetDefaultLocalEcho() {
-        val testHelper = CommonTestHelper(context())
+    fun test_SetDefaultLocalEcho() = runSessionTest(context()) { testHelper ->
 
         val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
 
@@ -170,19 +167,16 @@ class QuadSTests : InstrumentedTest {
         testHelper.runBlockingTest {
             quadS.setDefaultKey(TEST_KEY_ID)
         }
-
-        testHelper.signOutAndClose(aliceSession)
     }
 
     @Test
-    fun test_StoreSecretWithMultipleKey() {
-        val testHelper = CommonTestHelper(context())
+    fun test_StoreSecretWithMultipleKey() = runSessionTest(context()) { testHelper ->
 
         val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
         val keyId1 = "Key.1"
-        val key1Info = generatedSecret(aliceSession, keyId1, true)
+        val key1Info = generatedSecret(testHelper, aliceSession, keyId1, true)
         val keyId2 = "Key2"
-        val key2Info = generatedSecret(aliceSession, keyId2, true)
+        val key2Info = generatedSecret(testHelper, aliceSession, keyId2, true)
 
         val mySecretText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
 
@@ -191,8 +185,8 @@ class QuadSTests : InstrumentedTest {
                     "my.secret",
                     mySecretText.toByteArray().toBase64NoPadding(),
                     listOf(
-                            SharedSecretStorageService.KeyRef(keyId1, RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey)),
-                            SharedSecretStorageService.KeyRef(keyId2, RawBytesKeySpec.fromRecoveryKey(key2Info.recoveryKey))
+                            KeyRef(keyId1, RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey)),
+                            KeyRef(keyId2, RawBytesKeySpec.fromRecoveryKey(key2Info.recoveryKey))
                     )
             )
         }
@@ -221,19 +215,16 @@ class QuadSTests : InstrumentedTest {
                     RawBytesKeySpec.fromRecoveryKey(key2Info.recoveryKey)!!
             )
         }
-
-        testHelper.signOutAndClose(aliceSession)
     }
 
     @Test
     @Ignore("Test is working locally, not in GitHub actions")
-    fun test_GetSecretWithBadPassphrase() {
-        val testHelper = CommonTestHelper(context())
+    fun test_GetSecretWithBadPassphrase() = runSessionTest(context()) { testHelper ->
 
         val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true))
         val keyId1 = "Key.1"
         val passphrase = "The good pass phrase"
-        val key1Info = generatedSecretFromPassphrase(aliceSession, passphrase, keyId1, true)
+        val key1Info = generatedSecretFromPassphrase(testHelper, aliceSession, passphrase, keyId1, true)
 
         val mySecretText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
 
@@ -241,7 +232,7 @@ class QuadSTests : InstrumentedTest {
             aliceSession.sharedSecretStorageService().storeSecret(
                     "my.secret",
                     mySecretText.toByteArray().toBase64NoPadding(),
-                    listOf(SharedSecretStorageService.KeyRef(keyId1, RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey)))
+                    listOf(KeyRef(keyId1, RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey)))
             )
         }
 
@@ -275,13 +266,9 @@ class QuadSTests : InstrumentedTest {
                     )
             )
         }
-
-        testHelper.signOutAndClose(aliceSession)
     }
 
-    private fun assertAccountData(session: Session, type: String): UserAccountDataEvent {
-        val testHelper = CommonTestHelper(context())
-
+    private fun assertAccountData(testHelper: CommonTestHelper, session: Session, type: String): UserAccountDataEvent {
         var accountData: UserAccountDataEvent? = null
         testHelper.waitWithLatch {
             val liveAccountData = session.accountDataService().getLiveUserAccountDataEvent(type)
@@ -297,29 +284,27 @@ class QuadSTests : InstrumentedTest {
         return accountData!!
     }
 
-    private fun generatedSecret(session: Session, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo {
+    private fun generatedSecret(testHelper: CommonTestHelper, session: Session, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo {
         val quadS = session.sharedSecretStorageService()
-        val testHelper = CommonTestHelper(context())
 
         val creationInfo = testHelper.runBlockingTest {
             quadS.generateKey(keyId, null, keyId, emptyKeySigner)
         }
 
-        assertAccountData(session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId")
+        assertAccountData(testHelper, session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId")
 
         if (asDefault) {
             testHelper.runBlockingTest {
                 quadS.setDefaultKey(keyId)
             }
-            assertAccountData(session, DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
+            assertAccountData(testHelper, session, DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
         }
 
         return creationInfo
     }
 
-    private fun generatedSecretFromPassphrase(session: Session, passphrase: String, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo {
+    private fun generatedSecretFromPassphrase(testHelper: CommonTestHelper, session: Session, passphrase: String, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo {
         val quadS = session.sharedSecretStorageService()
-        val testHelper = CommonTestHelper(context())
 
         val creationInfo = testHelper.runBlockingTest {
             quadS.generateKeyWithPassphrase(
@@ -331,12 +316,12 @@ class QuadSTests : InstrumentedTest {
             )
         }
 
-        assertAccountData(session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId")
+        assertAccountData(testHelper, session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId")
         if (asDefault) {
             testHelper.runBlockingTest {
                 quadS.setDefaultKey(keyId)
             }
-            assertAccountData(session, DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
+            assertAccountData(testHelper, session, DefaultSharedSecretStorageService.DEFAULT_KEY_ID)
         }
 
         return creationInfo
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 2892cf846411d3dcaf273713d1184de254b02c57..c2e74abc59cd1729b821dc4bbc9d30f11a83f7e7 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
@@ -44,8 +44,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransa
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
 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.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
 import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationCancel
 import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationStart
 import org.matrix.android.sdk.internal.crypto.model.rest.toValue
@@ -53,12 +52,11 @@ import java.util.concurrent.CountDownLatch
 
 @RunWith(AndroidJUnit4::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Ignore
 class SASTest : InstrumentedTest {
 
     @Test
-    fun test_aliceStartThenAliceCancel() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun test_aliceStartThenAliceCancel() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
         val aliceSession = cryptoTestData.firstSession
@@ -135,15 +133,11 @@ class SASTest : InstrumentedTest {
 
         assertNull(bobVerificationService.getExistingTransaction(aliceSession.myUserId, txID))
         assertNull(aliceVerificationService.getExistingTransaction(bobSession.myUserId, txID))
-
-        cryptoTestData.cleanUp(testHelper)
     }
 
     @Test
     @Ignore("This test will be ignored until it is fixed")
-    fun test_key_agreement_protocols_must_include_curve25519() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun test_key_agreement_protocols_must_include_curve25519() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         fail("Not passing for the moment")
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
@@ -195,15 +189,11 @@ class SASTest : InstrumentedTest {
         testHelper.await(cancelLatch)
 
         assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod, cancelReason)
-
-        cryptoTestData.cleanUp(testHelper)
     }
 
     @Test
     @Ignore("This test will be ignored until it is fixed")
-    fun test_key_agreement_macs_Must_include_hmac_sha256() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun test_key_agreement_macs_Must_include_hmac_sha256() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         fail("Not passing for the moment")
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
@@ -236,15 +226,11 @@ class SASTest : InstrumentedTest {
 
         val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!!
         assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code)
-
-        cryptoTestData.cleanUp(testHelper)
     }
 
     @Test
     @Ignore("This test will be ignored until it is fixed")
-    fun test_key_agreement_short_code_include_decimal() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun test_key_agreement_short_code_include_decimal() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         fail("Not passing for the moment")
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
@@ -277,18 +263,18 @@ class SASTest : InstrumentedTest {
 
         val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!!
         assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code)
-
-        cryptoTestData.cleanUp(testHelper)
     }
 
-    private fun fakeBobStart(bobSession: Session,
-                             aliceUserID: String?,
-                             aliceDevice: String?,
-                             tid: String,
-                             protocols: List<String> = SASDefaultVerificationTransaction.KNOWN_AGREEMENT_PROTOCOLS,
-                             hashes: List<String> = SASDefaultVerificationTransaction.KNOWN_HASHES,
-                             mac: List<String> = SASDefaultVerificationTransaction.KNOWN_MACS,
-                             codes: List<String> = SASDefaultVerificationTransaction.KNOWN_SHORT_CODES) {
+    private fun fakeBobStart(
+            bobSession: Session,
+            aliceUserID: String?,
+            aliceDevice: String?,
+            tid: String,
+            protocols: List<String> = SASDefaultVerificationTransaction.KNOWN_AGREEMENT_PROTOCOLS,
+            hashes: List<String> = SASDefaultVerificationTransaction.KNOWN_HASHES,
+            mac: List<String> = SASDefaultVerificationTransaction.KNOWN_MACS,
+            codes: List<String> = SASDefaultVerificationTransaction.KNOWN_SHORT_CODES
+    ) {
         val startMessage = KeyVerificationStart(
                 fromDevice = bobSession.cryptoService().getMyDevice().deviceId,
                 method = VerificationMethod.SAS.toValue(),
@@ -314,9 +300,7 @@ class SASTest : InstrumentedTest {
     // any two devices may only have at most one key verification in flight at a time.
     // If a device has two verifications in progress with the same device, then it should cancel both verifications.
     @Test
-    fun test_aliceStartTwoRequests() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun test_aliceStartTwoRequests() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
         val aliceSession = cryptoTestData.firstSession
@@ -357,9 +341,7 @@ class SASTest : InstrumentedTest {
      */
     @Test
     @Ignore("This test will be ignored until it is fixed")
-    fun test_aliceAndBobAgreement() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun test_aliceAndBobAgreement() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
         val aliceSession = cryptoTestData.firstSession
@@ -413,14 +395,10 @@ class SASTest : InstrumentedTest {
         accepted!!.shortAuthenticationStrings.forEach {
             assertTrue("all agreed Short Code should be known by alice", startReq!!.shortAuthenticationStrings.contains(it))
         }
-
-        cryptoTestData.cleanUp(testHelper)
     }
 
     @Test
-    fun test_aliceAndBobSASCode() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun test_aliceAndBobSASCode() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
         val aliceSession = cryptoTestData.firstSession
@@ -437,7 +415,7 @@ class SASTest : InstrumentedTest {
                     OutgoingSasVerificationTransaction.UxState.SHOW_SAS -> {
                         aliceSASLatch.countDown()
                     }
-                    else                                                -> Unit
+                    else -> Unit
                 }
             }
         }
@@ -451,7 +429,7 @@ class SASTest : InstrumentedTest {
                     IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> {
                         tx.performAccept()
                     }
-                    else                                                   -> Unit
+                    else -> Unit
                 }
                 if (uxState === IncomingSasVerificationTransaction.UxState.SHOW_SAS) {
                     bobSASLatch.countDown()
@@ -473,14 +451,10 @@ class SASTest : InstrumentedTest {
                 "Should have same SAS", aliceTx.getShortCodeRepresentation(SasMode.DECIMAL),
                 bobTx.getShortCodeRepresentation(SasMode.DECIMAL)
         )
-
-        cryptoTestData.cleanUp(testHelper)
     }
 
     @Test
-    fun test_happyPath() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun test_happyPath() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
         val aliceSession = cryptoTestData.firstSession
@@ -505,7 +479,7 @@ class SASTest : InstrumentedTest {
                             aliceSASLatch.countDown()
                         }
                     }
-                    else                                                -> Unit
+                    else -> Unit
                 }
             }
         }
@@ -525,16 +499,16 @@ class SASTest : InstrumentedTest {
                             tx.performAccept()
                         }
                     }
-                    IncomingSasVerificationTransaction.UxState.SHOW_SAS    -> {
+                    IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
                         if (matchOnce) {
                             matchOnce = false
                             tx.userHasVerifiedShortCode()
                         }
                     }
-                    IncomingSasVerificationTransaction.UxState.VERIFIED    -> {
+                    IncomingSasVerificationTransaction.UxState.VERIFIED -> {
                         bobSASLatch.countDown()
                     }
-                    else                                                   -> Unit
+                    else -> Unit
                 }
             }
         }
@@ -553,13 +527,10 @@ class SASTest : InstrumentedTest {
 
         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)
-        cryptoTestData.cleanUp(testHelper)
     }
 
     @Test
-    fun test_ConcurrentStart() {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    fun test_ConcurrentStart() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
         val aliceSession = cryptoTestData.firstSession
@@ -646,7 +617,5 @@ class SASTest : InstrumentedTest {
                 bobPovTx?.state == VerificationTxState.ShortCodeReady
             }
         }
-
-        cryptoTestData.cleanUp(testHelper)
     }
 }
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 df3b2ffe276d2e982eb79963add0dcec97ad1d40..3f229069653067c43b4e0b13c1d5c95d72519994 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,6 +19,7 @@ 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
@@ -27,11 +28,13 @@ 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.session.crypto.verification.CancelCode
 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.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
+import org.matrix.android.sdk.common.SessionTestParams
 import org.matrix.android.sdk.common.TestConstants
 import java.util.concurrent.CountDownLatch
 import kotlin.coroutines.Continuation
@@ -39,6 +42,7 @@ import kotlin.coroutines.resume
 
 @RunWith(AndroidJUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
+@Ignore
 class VerificationTest : InstrumentedTest {
 
     data class ExpectedResult(
@@ -149,12 +153,12 @@ class VerificationTest : InstrumentedTest {
 
     // TODO Add tests without SAS
 
-    private fun doTest(aliceSupportedMethods: List<VerificationMethod>,
-                       bobSupportedMethods: List<VerificationMethod>,
-                       expectedResultForAlice: ExpectedResult,
-                       expectedResultForBob: ExpectedResult) {
-        val testHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(testHelper)
+    private fun doTest(
+            aliceSupportedMethods: List<VerificationMethod>,
+            bobSupportedMethods: List<VerificationMethod>,
+            expectedResultForAlice: ExpectedResult,
+            expectedResultForBob: ExpectedResult
+    ) = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
 
         val aliceSession = cryptoTestData.firstSession
@@ -249,7 +253,48 @@ class VerificationTest : InstrumentedTest {
             pr.otherCanShowQrCode() shouldBe expectedResultForBob.otherCanShowQrCode
             pr.otherCanScanQrCode() shouldBe expectedResultForBob.otherCanScanQrCode
         }
+    }
+
+    @Test
+    fun test_selfVerificationAcceptedCancelsItForOtherSessions() = runSessionTest(context()) { testHelper ->
+        val defaultSessionParams = SessionTestParams(true)
+
+        val aliceSessionToVerify = testHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams)
+        val aliceSessionThatVerifies = testHelper.logIntoAccount(aliceSessionToVerify.myUserId, TestConstants.PASSWORD, defaultSessionParams)
+        val aliceSessionThatReceivesCanceledEvent = testHelper.logIntoAccount(aliceSessionToVerify.myUserId, TestConstants.PASSWORD, defaultSessionParams)
+
+        val verificationMethods = listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SCAN, VerificationMethod.QR_CODE_SHOW)
+
+        val serviceOfVerified = aliceSessionToVerify.cryptoService().verificationService()
+        val serviceOfVerifier = aliceSessionThatVerifies.cryptoService().verificationService()
+        val serviceOfUserWhoReceivesCancellation = aliceSessionThatReceivesCanceledEvent.cryptoService().verificationService()
+
+        serviceOfVerifier.addListener(object : VerificationService.Listener {
+            override fun verificationRequestCreated(pr: PendingVerificationRequest) {
+                // Accept verification request
+                serviceOfVerifier.readyPendingVerification(
+                        verificationMethods,
+                        pr.otherUserId,
+                        pr.transactionId!!,
+                )
+            }
+        })
+
+        serviceOfVerified.requestKeyVerification(
+                methods = verificationMethods,
+                otherUserId = aliceSessionToVerify.myUserId,
+                otherDevices = listOfNotNull(aliceSessionThatVerifies.sessionParams.deviceId, aliceSessionThatReceivesCanceledEvent.sessionParams.deviceId),
+        )
+
+        testHelper.waitWithLatch { latch ->
+            testHelper.retryPeriodicallyWithLatch(latch) {
+                val requests = serviceOfUserWhoReceivesCancellation.getExistingVerificationRequests(aliceSessionToVerify.myUserId)
+                requests.any { it.cancelConclusion == CancelCode.AcceptedByAnotherDevice }
+            }
+        }
 
-        cryptoTestData.cleanUp(testHelper)
+        testHelper.signOutAndClose(aliceSessionToVerify)
+        testHelper.signOutAndClose(aliceSessionThatVerifies)
+        testHelper.signOutAndClose(aliceSessionThatReceivesCanceledEvent)
     }
 }
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 acb23bf72382776d55b9f2f68eb352220417eaeb..0560cfec95f10f4e3e975b92c25565e89ee1d7e3 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
@@ -289,9 +289,11 @@ class MarkdownParserTest : InstrumentedTest {
         markdownParser.parse(text).expect(text, null)
     }
 
-    private fun testType(name: String,
-                         markdownPattern: String,
-                         htmlExpectedTag: String) {
+    private fun testType(
+            name: String,
+            markdownPattern: String,
+            htmlExpectedTag: String
+    ) {
         // Test simple case
         "$markdownPattern$name$markdownPattern"
                 .let {
@@ -376,10 +378,12 @@ class MarkdownParserTest : InstrumentedTest {
                 }
     }
 
-    private fun testTypeNewLines(name: String,
-                                 markdownPattern: String,
-                                 htmlExpectedTag: String,
-                                 softBreak: String = "<br />") {
+    private fun testTypeNewLines(
+            name: String,
+            markdownPattern: String,
+            htmlExpectedTag: String,
+            softBreak: String = "<br />"
+    ) {
         // With new line inside the block
         "$markdownPattern$name\n$name$markdownPattern"
                 .let {
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/TestPermalinkService.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/TestPermalinkService.kt
index 2f9a5e0a73a656f0f00dfdf048fafd85b5e252d2..3a267ec694bec4ecd0346faf24acb62fbf223ada 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/TestPermalinkService.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/TestPermalinkService.kt
@@ -44,7 +44,7 @@ class TestPermalinkService : PermalinkService {
 
     override fun createMentionSpanTemplate(type: PermalinkService.SpanTemplateType, forceMatrixTo: Boolean): String {
         return when (type) {
-            HTML     -> "<a href=\"https://matrix.to/#/%1\$s\">%2\$s</a>"
+            HTML -> "<a href=\"https://matrix.to/#/%1\$s\">%2\$s</a>"
             MARKDOWN -> "[%2\$s](https://matrix.to/#/%1\$s)"
         }
     }
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 a2984dd27e2de8d27d082e5df6579049a8f3e456..45bd38870d3921c2b09a7c74353a807c9b88dcc1 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
@@ -34,8 +34,7 @@ import org.matrix.android.sdk.api.session.events.model.isThread
 import org.matrix.android.sdk.api.session.getRoom
 import org.matrix.android.sdk.api.session.room.timeline.Timeline
 import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
-import org.matrix.android.sdk.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
 import java.util.concurrent.CountDownLatch
 
 @RunWith(JUnit4::class)
@@ -44,9 +43,7 @@ import java.util.concurrent.CountDownLatch
 class ThreadMessagingTest : InstrumentedTest {
 
     @Test
-    fun reply_in_thread_should_create_a_thread() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    fun reply_in_thread_should_create_a_thread() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(false)
 
         val aliceSession = cryptoTestData.firstSession
@@ -86,7 +83,7 @@ class ThreadMessagingTest : InstrumentedTest {
         val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
         timeline.start()
 
-        aliceSession.startSync(true)
+        aliceSession.syncService().startSync(true)
         run {
             val lock = CountDownLatch(1)
             val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@@ -100,13 +97,11 @@ class ThreadMessagingTest : InstrumentedTest {
             timeline.addListener(eventsListener)
             commonTestHelper.await(lock, 600_000)
         }
-        aliceSession.stopSync()
+        aliceSession.syncService().stopSync()
     }
 
     @Test
-    fun reply_in_thread_should_create_a_thread_from_other_user() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    fun reply_in_thread_should_create_a_thread_from_other_user() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false)
 
         val aliceSession = cryptoTestData.firstSession
@@ -149,7 +144,7 @@ class ThreadMessagingTest : InstrumentedTest {
         val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
         timeline.start()
 
-        aliceSession.startSync(true)
+        aliceSession.syncService().startSync(true)
         run {
             val lock = CountDownLatch(1)
             val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@@ -161,9 +156,9 @@ class ThreadMessagingTest : InstrumentedTest {
             timeline.addListener(eventsListener)
             commonTestHelper.await(lock, 600_000)
         }
-        aliceSession.stopSync()
+        aliceSession.syncService().stopSync()
 
-        bobSession.startSync(true)
+        bobSession.syncService().startSync(true)
         run {
             val lock = CountDownLatch(1)
             val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@@ -175,13 +170,11 @@ class ThreadMessagingTest : InstrumentedTest {
             timeline.addListener(eventsListener)
             commonTestHelper.await(lock, 600_000)
         }
-        bobSession.stopSync()
+        bobSession.syncService().stopSync()
     }
 
     @Test
-    fun reply_in_thread_to_timeline_message_multiple_times() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    fun reply_in_thread_to_timeline_message_multiple_times() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(false)
 
         val aliceSession = cryptoTestData.firstSession
@@ -224,7 +217,7 @@ class ThreadMessagingTest : InstrumentedTest {
         val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
         timeline.start()
 
-        aliceSession.startSync(true)
+        aliceSession.syncService().startSync(true)
         run {
             val lock = CountDownLatch(1)
             val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@@ -240,13 +233,11 @@ class ThreadMessagingTest : InstrumentedTest {
             timeline.addListener(eventsListener)
             commonTestHelper.await(lock, 600_000)
         }
-        aliceSession.stopSync()
+        aliceSession.syncService().stopSync()
     }
 
     @Test
-    fun thread_summary_advanced_validation_after_multiple_messages_in_multiple_threads() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    fun thread_summary_advanced_validation_after_multiple_messages_in_multiple_threads() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false)
 
         val aliceSession = cryptoTestData.firstSession
@@ -323,7 +314,7 @@ class ThreadMessagingTest : InstrumentedTest {
         val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
         timeline.start()
 
-        aliceSession.startSync(true)
+        aliceSession.syncService().startSync(true)
         run {
             val lock = CountDownLatch(1)
             val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
@@ -347,6 +338,6 @@ class ThreadMessagingTest : InstrumentedTest {
             timeline.addListener(eventsListener)
             commonTestHelper.await(lock, 600_000)
         }
-        aliceSession.stopSync()
+        aliceSession.syncService().stopSync()
     }
 }
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 94b2ba55a3456bdbacd1e47958b96a55b6a0bd0f..7b0d57abbcfa117b66166e8ef66edadfaca7e7c9 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
@@ -22,7 +22,6 @@ import io.realm.Realm
 import io.realm.RealmConfiguration
 import io.realm.kotlin.createObject
 import org.amshove.kluent.shouldBeEqualTo
-import org.amshove.kluent.shouldBeTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -30,13 +29,11 @@ import org.matrix.android.sdk.InstrumentedTest
 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.helper.addTimelineEvent
-import org.matrix.android.sdk.internal.database.helper.merge
 import org.matrix.android.sdk.internal.database.mapper.toEntity
 import org.matrix.android.sdk.internal.database.model.ChunkEntity
 import org.matrix.android.sdk.internal.database.model.SessionRealmModule
 import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
 import org.matrix.android.sdk.internal.util.time.DefaultClock
-import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeListOfEvents
 import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeMessageEvent
 
 @RunWith(AndroidJUnit4::class)
@@ -97,66 +94,11 @@ internal class ChunkEntityTest : InstrumentedTest {
         }
     }
 
-    @Test
-    fun merge_shouldAddEvents_whenMergingBackward() {
-        monarchy.runTransactionSync { realm ->
-            val chunk1: ChunkEntity = realm.createObject()
-            val chunk2: ChunkEntity = realm.createObject()
-            chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
-            chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
-            chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
-            chunk1.timelineEvents.size shouldBeEqualTo 60
-        }
-    }
-
-    @Test
-    fun merge_shouldAddOnlyDifferentEvents_whenMergingBackward() {
-        monarchy.runTransactionSync { realm ->
-            val chunk1: ChunkEntity = realm.createObject()
-            val chunk2: ChunkEntity = realm.createObject()
-            val eventsForChunk1 = createFakeListOfEvents(30)
-            val eventsForChunk2 = eventsForChunk1 + createFakeListOfEvents(10)
-            chunk1.isLastForward = true
-            chunk2.isLastForward = false
-            chunk1.addAll(ROOM_ID, eventsForChunk1, PaginationDirection.FORWARDS)
-            chunk2.addAll(ROOM_ID, eventsForChunk2, PaginationDirection.BACKWARDS)
-            chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
-            chunk1.timelineEvents.size shouldBeEqualTo 40
-            chunk1.isLastForward.shouldBeTrue()
-        }
-    }
-
-    @Test
-    fun merge_shouldPrevTokenMerged_whenMergingForwards() {
-        monarchy.runTransactionSync { realm ->
-            val chunk1: ChunkEntity = realm.createObject()
-            val chunk2: ChunkEntity = realm.createObject()
-            val prevToken = "prev_token"
-            chunk1.prevToken = prevToken
-            chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
-            chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
-            chunk1.merge(ROOM_ID, chunk2, PaginationDirection.FORWARDS)
-            chunk1.prevToken shouldBeEqualTo prevToken
-        }
-    }
-
-    @Test
-    fun merge_shouldNextTokenMerged_whenMergingBackwards() {
-        monarchy.runTransactionSync { realm ->
-            val chunk1: ChunkEntity = realm.createObject()
-            val chunk2: ChunkEntity = realm.createObject()
-            val nextToken = "next_token"
-            chunk1.nextToken = nextToken
-            chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
-            chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
-            chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
-            chunk1.nextToken shouldBeEqualTo nextToken
-        }
-    }
-
-    private fun ChunkEntity.addAll(roomId: String,
-                                   events: List<Event>,
-                                   direction: PaginationDirection) {
+    private fun ChunkEntity.addAll(
+            roomId: String,
+            events: List<Event>,
+            direction: PaginationDirection
+    ) {
         events.forEach { event ->
             val fakeEvent = event.toEntity(roomId, SendState.SYNCED, clock.epochMillis()).let {
                 realm.copyToRealm(it)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/FakeTokenChunkEvent.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/FakeTokenChunkEvent.kt
index 657f622c5b75f7603cb7132596f3ac6ed877472a..2e9478ba7ececeab27990826fa1db11e3f3a100c 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/FakeTokenChunkEvent.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/FakeTokenChunkEvent.kt
@@ -19,8 +19,9 @@ package org.matrix.android.sdk.session.room.timeline
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.internal.session.room.timeline.TokenChunkEvent
 
-internal data class FakeTokenChunkEvent(override val start: String?,
-                                        override val end: String?,
-                                        override val events: List<Event> = emptyList(),
-                                        override val stateEvents: List<Event> = emptyList()
+internal data class FakeTokenChunkEvent(
+        override val start: String?,
+        override val end: String?,
+        override val events: List<Event> = emptyList(),
+        override val stateEvents: List<Event> = emptyList()
 ) : TokenChunkEvent
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/PollAggregationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/PollAggregationTest.kt
index 61ab6d4b40f301673ac6c32c804f6875ff6e8513..a37d2ce015f68a624c39d8cc944b49a8ec0fbba6 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/PollAggregationTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/PollAggregationTest.kt
@@ -38,8 +38,7 @@ import org.matrix.android.sdk.api.session.room.model.message.PollType
 import org.matrix.android.sdk.api.session.room.timeline.Timeline
 import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
-import org.matrix.android.sdk.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
 import java.util.concurrent.CountDownLatch
 
 @RunWith(JUnit4::class)
@@ -47,9 +46,7 @@ import java.util.concurrent.CountDownLatch
 class PollAggregationTest : InstrumentedTest {
 
     @Test
-    fun testAllPollUseCases() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    fun testAllPollUseCases() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false)
 
         val aliceSession = cryptoTestData.firstSession
@@ -60,7 +57,7 @@ class PollAggregationTest : InstrumentedTest {
         // Bob creates a poll
         roomFromBobPOV.sendService().sendPoll(PollType.DISCLOSED, pollQuestion, pollOptions)
 
-        aliceSession.startSync(true)
+        aliceSession.syncService().startSync(true)
         val aliceTimeline = roomFromAlicePOV.timelineService().createTimeline(null, TimelineSettings(30))
         aliceTimeline.start()
 
@@ -80,7 +77,7 @@ class PollAggregationTest : InstrumentedTest {
                     }
 
                     when (lock.count.toInt()) {
-                        TOTAL_TEST_COUNT     -> {
+                        TOTAL_TEST_COUNT -> {
                             // Poll has just been created.
                             testInitialPollConditions(pollContent, pollSummary)
                             lock.countDown()
@@ -122,7 +119,7 @@ class PollAggregationTest : InstrumentedTest {
                             testEndedPoll(pollSummary)
                             lock.countDown()
                         }
-                        else                 -> {
+                        else -> {
                             fail("Lock count ${lock.count} didn't handled.")
                         }
                     }
@@ -136,9 +133,8 @@ class PollAggregationTest : InstrumentedTest {
 
         aliceTimeline.removeAllListeners()
 
-        aliceSession.stopSync()
+        aliceSession.syncService().stopSync()
         aliceTimeline.dispose()
-        cryptoTestData.cleanUp(commonTestHelper)
     }
 
     private fun testInitialPollConditions(pollContent: MessagePollContent, pollSummary: PollResponseAggregatedSummary?) {
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/RoomDataHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/RoomDataHelper.kt
index 8a4429db456b7845f380ade3c3e5697718ec2b7e..53585ae82abc743a2ca79bf82663d730a301dabd 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/RoomDataHelper.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/RoomDataHelper.kt
@@ -41,11 +41,12 @@ object RoomDataHelper {
         }
     }
 
-    private fun createFakeEvent(type: String,
-                                content: Content? = null,
-                                prevContent: Content? = null,
-                                sender: String = FAKE_TEST_SENDER,
-                                stateKey: String? = null
+    private fun createFakeEvent(
+            type: String,
+            content: Content? = null,
+            prevContent: Content? = null,
+            sender: String = FAKE_TEST_SENDER,
+            stateKey: String? = null
     ): Event {
         return Event(
                 type = type,
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 d5b4a07fc0fd19a43c625acbfeb15c14a8c0d12a..3dbf206e089c12815ecf89dd0ce9c8ebab86e306 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
@@ -34,8 +34,7 @@ import org.matrix.android.sdk.api.session.getRoom
 import org.matrix.android.sdk.api.session.room.model.message.MessageContent
 import org.matrix.android.sdk.api.session.room.timeline.Timeline
 import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
-import org.matrix.android.sdk.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
 import org.matrix.android.sdk.common.checkSendOrder
 import timber.log.Timber
 import java.util.concurrent.CountDownLatch
@@ -53,9 +52,7 @@ class TimelineForwardPaginationTest : InstrumentedTest {
      * This test ensure that if we click to permalink, we will be able to go back to the live
      */
     @Test
-    fun forwardPaginationTest() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    fun forwardPaginationTest() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
         val numberOfMessagesToSend = 90
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(false)
 
@@ -140,9 +137,24 @@ class TimelineForwardPaginationTest : InstrumentedTest {
             aliceTimeline.hasMoreToLoad(Timeline.Direction.BACKWARDS).shouldBeFalse()
 
             assertEquals(EventType.STATE_ROOM_CREATE, snapshot.lastOrNull()?.root?.getClearType())
-            // 6 for room creation item (backward pagination), 1 for the context, and 50 for the forward pagination
-            // 6 + 1 + 50
-            assertEquals(57, snapshot.size)
+
+            // We explicitly test all the types we expect here, as we expect 51 messages and "some" state events
+            // But state events can change over time. So this acts as a kinda documentation of what we expect and
+            // provides a good error message if it doesn't match
+
+            val snapshotTypes = mutableMapOf<String?, Int>()
+            snapshot.groupingBy { it -> it.root.type }.eachCountTo(snapshotTypes)
+            // Some state events on room creation
+            assertEquals("m.room.name", 1, snapshotTypes.remove("m.room.name"))
+            assertEquals("m.room.guest_access", 1, snapshotTypes.remove("m.room.guest_access"))
+            assertEquals("m.room.history_visibility", 1, snapshotTypes.remove("m.room.history_visibility"))
+            assertEquals("m.room.join_rules", 1, snapshotTypes.remove("m.room.join_rules"))
+            assertEquals("m.room.power_levels", 1, snapshotTypes.remove("m.room.power_levels"))
+            assertEquals("m.room.create", 1, snapshotTypes.remove("m.room.create"))
+            assertEquals("m.room.member", 1, snapshotTypes.remove("m.room.member"))
+            // 50 from pagination + 1 context
+            assertEquals("m.room.message", 51, snapshotTypes.remove("m.room.message"))
+            assertEquals("Additional events found in timeline", setOf<String>(), snapshotTypes.keys)
         }
 
         // Alice paginates once again FORWARD for 50 events
@@ -151,9 +163,11 @@ class TimelineForwardPaginationTest : InstrumentedTest {
             // Ask for a forward pagination
             val snapshot = runBlocking {
                 aliceTimeline.awaitPaginate(Timeline.Direction.FORWARDS, 50)
+                // We should paginate one more time to check we are at the end now that chunks are not merged.
+                aliceTimeline.awaitPaginate(Timeline.Direction.FORWARDS, 50)
             }
-            // 6 for room creation item (backward pagination),and numberOfMessagesToSend (all the message of the room)
-            snapshot.size == 6 + numberOfMessagesToSend &&
+            // 7 for room creation item (backward pagination),and numberOfMessagesToSend (all the message of the room)
+            snapshot.size == 7 + numberOfMessagesToSend &&
                     snapshot.checkSendOrder(message, numberOfMessagesToSend, 0)
 
             // The timeline is fully loaded
@@ -162,7 +176,5 @@ class TimelineForwardPaginationTest : InstrumentedTest {
         }
 
         aliceTimeline.dispose()
-
-        cryptoTestData.cleanUp(commonTestHelper)
     }
 }
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 6e5fed8df9f2f2c11125f525f80fc0e07ca6db14..7c1a097b2419f80839260ba467464e5fefe48296 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
@@ -20,6 +20,7 @@ import androidx.test.filters.LargeTest
 import org.amshove.kluent.shouldBeFalse
 import org.amshove.kluent.shouldBeTrue
 import org.junit.FixMethodOrder
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -33,13 +34,13 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent
 import org.matrix.android.sdk.api.session.room.timeline.Timeline
 import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
 import org.matrix.android.sdk.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
 import org.matrix.android.sdk.common.checkSendOrder
 import timber.log.Timber
 import java.util.concurrent.CountDownLatch
 
 @RunWith(JUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
+@Ignore("This test will be ignored until it is fixed")
 @LargeTest
 class TimelinePreviousLastForwardTest : InstrumentedTest {
 
@@ -48,9 +49,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
      */
 
     @Test
-    fun previousLastForwardTest() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    fun previousLastForwardTest() = CommonTestHelper.runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false)
 
         val aliceSession = cryptoTestData.firstSession
@@ -74,8 +73,12 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
                     Timber.w(" event ${it.root}")
                 }
 
-                // Ok, we have the 8 first messages of the initial sync (room creation and bob invite and join events)
-                snapshot.size == 8
+                // Ok, we have the 9 first messages of the initial sync (room creation and bob invite and join events)
+                // create
+                // join alice
+                // power_levels, join_rules, history_visibility, guest_access, name
+                // invite, join bob
+                snapshot.size == 9
             }
 
             bobTimeline.addListener(eventsListener)
@@ -87,7 +90,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
         }
 
         // Bob stop to sync
-        bobSession.stopSync()
+        bobSession.syncService().stopSync()
 
         val firstMessage = "First messages from Alice"
         // Alice sends 30 messages
@@ -100,7 +103,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
                 .eventId
 
         // Bob start to sync
-        bobSession.startSync(true)
+        bobSession.syncService().startSync(true)
 
         run {
             val lock = CountDownLatch(1)
@@ -124,7 +127,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
         }
 
         // Bob stop to sync
-        bobSession.stopSync()
+        bobSession.syncService().stopSync()
 
         val secondMessage = "Second messages from Alice"
         // Alice sends again 30 messages
@@ -135,7 +138,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
         )
 
         // Bob start to sync
-        bobSession.startSync(true)
+        bobSession.syncService().startSync(true)
 
         run {
             val lock = CountDownLatch(1)
@@ -192,7 +195,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
                     Timber.w(" event ${it.root}")
                 }
 
-                snapshot.size == 44 // 8 + 1 + 35
+                snapshot.size == 45 // 9 + 1 + 35
             }
 
             bobTimeline.addListener(eventsListener)
@@ -220,14 +223,15 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
 
                 // Bob can see the first event of the room (so Back pagination has worked)
                 snapshot.lastOrNull()?.root?.getClearType() == EventType.STATE_ROOM_CREATE &&
-                        // 8 for room creation item 60 message from Alice
-                        snapshot.size == 68 && // 8 + 60
+                        // 9 for room creation item 60 message from Alice
+                        snapshot.size == 69 && // 9 + 60U
                         snapshot.checkSendOrder(secondMessage, 30, 0) &&
                         snapshot.checkSendOrder(firstMessage, 30, 30)
             }
 
             bobTimeline.addListener(eventsListener)
 
+            bobTimeline.paginate(Timeline.Direction.FORWARDS, 50)
             bobTimeline.paginate(Timeline.Direction.FORWARDS, 50)
 
             commonTestHelper.await(lock)
@@ -238,7 +242,5 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
         }
 
         bobTimeline.dispose()
-
-        cryptoTestData.cleanUp(commonTestHelper)
     }
 }
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 42f710d7cf431f2a90f14fb56e8b61b05cea4674..59b3b1453229c135340bba60a27f831b0ca78c22 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
@@ -20,6 +20,7 @@ import androidx.test.filters.LargeTest
 import kotlinx.coroutines.runBlocking
 import org.amshove.kluent.internal.assertEquals
 import org.junit.FixMethodOrder
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -32,19 +33,17 @@ import org.matrix.android.sdk.api.session.getRoom
 import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
 import org.matrix.android.sdk.api.session.room.timeline.Timeline
 import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
-import org.matrix.android.sdk.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
 import org.matrix.android.sdk.common.TestConstants
 
 @RunWith(JUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
 @LargeTest
+@Ignore
 class TimelineSimpleBackPaginationTest : InstrumentedTest {
 
     @Test
-    fun timeline_backPaginate_shouldReachEndOfTimeline() {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    fun timeline_backPaginate_shouldReachEndOfTimeline() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
         val numberOfMessagesToSent = 200
 
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false)
@@ -102,6 +101,5 @@ class TimelineSimpleBackPaginationTest : InstrumentedTest {
         assertEquals(numberOfMessagesToSent, onlySentEvents.size)
 
         bobTimeline.dispose()
-        cryptoTestData.cleanUp(commonTestHelper)
     }
 }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt
index 02430dda745a541292cdcb9f079c2b328504846c..27ea0e1c3c07743a10a892a7a498accfa1fcc9ff 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt
@@ -30,8 +30,7 @@ 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.model.message.MessageContent
 import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
-import org.matrix.android.sdk.common.CommonTestHelper
-import org.matrix.android.sdk.common.CryptoTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
 import java.util.concurrent.CountDownLatch
 
 /** !! Not working with the new timeline
@@ -47,15 +46,12 @@ class TimelineWithManyMembersTest : InstrumentedTest {
         private const val NUMBER_OF_MEMBERS = 6
     }
 
-    private val commonTestHelper = CommonTestHelper(context())
-    private val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
-
     /**
      * Ensures when someone sends a message to a crowded room, everyone can decrypt the message.
      */
 
     @Test
-    fun everyone_should_decrypt_message_in_a_crowded_room() {
+    fun everyone_should_decrypt_message_in_a_crowded_room() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithManyMembers(NUMBER_OF_MEMBERS)
 
         val sessionForFirstMember = cryptoTestData.firstSession
@@ -75,7 +71,7 @@ class TimelineWithManyMembersTest : InstrumentedTest {
             val timelineForCurrentMember = roomForCurrentMember.timelineService().createTimeline(null, TimelineSettings(30))
             timelineForCurrentMember.start()
 
-            session.startSync(true)
+            session.syncService().startSync(true)
 
             run {
                 val lock = CountDownLatch(1)
@@ -96,7 +92,7 @@ class TimelineWithManyMembersTest : InstrumentedTest {
                 timelineForCurrentMember.addListener(eventsListener)
                 commonTestHelper.await(lock, 600_000)
             }
-            session.stopSync()
+            session.syncService().stopSync()
         }
     }
 }
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 e17b7efbd6d9d348c39ebb02ba9c99fc625b1bdc..7c97426c391a675f4c2659b030e12ef214162eb6 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
@@ -26,9 +26,8 @@ import org.matrix.android.sdk.InstrumentedTest
 import org.matrix.android.sdk.api.extensions.orFalse
 import org.matrix.android.sdk.api.session.getRoom
 import org.matrix.android.sdk.api.session.search.SearchResult
-import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
 import org.matrix.android.sdk.common.CryptoTestData
-import org.matrix.android.sdk.common.CryptoTestHelper
 
 @RunWith(JUnit4::class)
 @FixMethodOrder(MethodSorters.JVM)
@@ -74,9 +73,7 @@ class SearchMessagesTest : InstrumentedTest {
         }
     }
 
-    private fun doTest(block: suspend (CryptoTestData) -> SearchResult) {
-        val commonTestHelper = CommonTestHelper(context())
-        val cryptoTestHelper = CryptoTestHelper(commonTestHelper)
+    private fun doTest(block: suspend (CryptoTestData) -> SearchResult) = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper ->
         val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(false)
         val aliceSession = cryptoTestData.firstSession
         val aliceRoomId = cryptoTestData.roomId
@@ -99,7 +96,5 @@ class SearchMessagesTest : InstrumentedTest {
                             (it.event.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse()
                         }.orFalse()
         )
-
-        cryptoTestData.cleanUp(commonTestHelper)
     }
 }
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt
index b9760c1bfc73f57903a33e04900ae8ddac92d080..0cc0ef57c411e7585ac56ed889e18603551f0d0f 100644
--- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt
+++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt
@@ -22,6 +22,7 @@ import kotlinx.coroutines.runBlocking
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertNotNull
 import org.junit.FixMethodOrder
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -40,7 +41,7 @@ import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
 import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
 import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
 import org.matrix.android.sdk.api.session.space.JoinSpaceResult
-import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
 import org.matrix.android.sdk.common.SessionTestParams
 
 @RunWith(JUnit4::class)
@@ -49,8 +50,7 @@ import org.matrix.android.sdk.common.SessionTestParams
 class SpaceCreationTest : InstrumentedTest {
 
     @Test
-    fun createSimplePublicSpace() {
-        val commonTestHelper = CommonTestHelper(context())
+    fun createSimplePublicSpace() = runSessionTest(context()) { commonTestHelper ->
         val session = commonTestHelper.createAccount("Hubble", SessionTestParams(true))
         val roomName = "My Space"
         val topic = "A public space for test"
@@ -96,13 +96,11 @@ class SpaceCreationTest : InstrumentedTest {
                 ?.toModel<RoomHistoryVisibilityContent>()?.historyVisibility
 
         assertEquals("Public space room should be world readable", RoomHistoryVisibility.WORLD_READABLE, historyVisibility)
-
-        commonTestHelper.signOutAndClose(session)
     }
 
     @Test
-    fun testJoinSimplePublicSpace() {
-        val commonTestHelper = CommonTestHelper(context())
+    @Ignore
+    fun testJoinSimplePublicSpace() = runSessionTest(context()) { commonTestHelper ->
 
         val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
         val bobSession = commonTestHelper.createAccount("bob", SessionTestParams(true))
@@ -134,8 +132,7 @@ class SpaceCreationTest : InstrumentedTest {
     }
 
     @Test
-    fun testSimplePublicSpaceWithChildren() {
-        val commonTestHelper = CommonTestHelper(context())
+    fun testSimplePublicSpaceWithChildren() = runSessionTest(context()) { commonTestHelper ->
         val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
         val bobSession = commonTestHelper.createAccount("bob", SessionTestParams(true))
 
@@ -204,8 +201,5 @@ class SpaceCreationTest : InstrumentedTest {
 //        ).size
 //
 //        assertEquals("Unexpected number of joined children", 1, childCount)
-
-        commonTestHelper.signOutAndClose(aliceSession)
-        commonTestHelper.signOutAndClose(bobSession)
     }
 }
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 6a17cb74add602e49100d148a961a6615fe2c450..5396251438d56fbe6d230220f833f0851a0e78c2 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
@@ -29,8 +29,8 @@ import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 import org.junit.runners.MethodSorters
 import org.matrix.android.sdk.InstrumentedTest
-import org.matrix.android.sdk.api.query.ActiveSpaceFilter
 import org.matrix.android.sdk.api.query.QueryStringValue
+import org.matrix.android.sdk.api.query.SpaceFilter
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.toContent
@@ -48,6 +48,7 @@ import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
 import org.matrix.android.sdk.api.session.room.powerlevels.Role
 import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
 import org.matrix.android.sdk.common.CommonTestHelper
+import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
 import org.matrix.android.sdk.common.SessionTestParams
 
 @RunWith(JUnit4::class)
@@ -55,8 +56,7 @@ import org.matrix.android.sdk.common.SessionTestParams
 class SpaceHierarchyTest : InstrumentedTest {
 
     @Test
-    fun createCanonicalChildRelation() {
-        val commonTestHelper = CommonTestHelper(context())
+    fun createCanonicalChildRelation() = runSessionTest(context()) { commonTestHelper ->
 
         val session = commonTestHelper.createAccount("John", SessionTestParams(true))
         val spaceName = "My Space"
@@ -173,8 +173,7 @@ class SpaceHierarchyTest : InstrumentedTest {
 //    }
 
     @Test
-    fun testFilteringBySpace() {
-        val commonTestHelper = CommonTestHelper(context())
+    fun testFilteringBySpace() = CommonTestHelper.runSessionTest(context()) { commonTestHelper ->
         val session = commonTestHelper.createAccount("John", SessionTestParams(true))
 
         val spaceAInfo = createPublicSpace(
@@ -185,12 +184,12 @@ class SpaceHierarchyTest : InstrumentedTest {
         )
 
         /* val spaceBInfo = */ createPublicSpace(
-                session, "SpaceB", listOf(
-                Triple("B1", true /*auto-join*/, true/*canonical*/),
-                Triple("B2", true, true),
-                Triple("B3", true, true)
-        )
-        )
+            session, "SpaceB", listOf(
+            Triple("B1", true /*auto-join*/, true/*canonical*/),
+            Triple("B2", true, true),
+            Triple("B3", true, true)
+    )
+    )
 
         val spaceCInfo = createPublicSpace(
                 session, "SpaceC", listOf(
@@ -249,15 +248,14 @@ class SpaceHierarchyTest : InstrumentedTest {
 
         Thread.sleep(6_000)
         val orphansUpdate = session.roomService().getRoomSummaries(roomSummaryQueryParams {
-            activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null)
+            spaceFilter = SpaceFilter.OrphanRooms
         })
         assertEquals("Unexpected number of orphan rooms ${orphansUpdate.map { it.name }}", 2, orphansUpdate.size)
     }
 
     @Test
     @Ignore("This test will be ignored until it is fixed")
-    fun testBreakCycle() {
-        val commonTestHelper = CommonTestHelper(context())
+    fun testBreakCycle() = CommonTestHelper.runSessionTest(context()) { commonTestHelper ->
         val session = commonTestHelper.createAccount("John", SessionTestParams(true))
 
         val spaceAInfo = createPublicSpace(
@@ -302,8 +300,7 @@ class SpaceHierarchyTest : InstrumentedTest {
     }
 
     @Test
-    fun testLiveFlatChildren() {
-        val commonTestHelper = CommonTestHelper(context())
+    fun testLiveFlatChildren() = CommonTestHelper.runSessionTest(context()) { commonTestHelper ->
         val session = commonTestHelper.createAccount("John", SessionTestParams(true))
 
         val spaceAInfo = createPublicSpace(
@@ -390,84 +387,87 @@ class SpaceHierarchyTest : InstrumentedTest {
             val roomIds: List<String>
     )
 
-    private fun createPublicSpace(session: Session,
-                                  spaceName: String,
-                                  childInfo: List<Triple<String, Boolean, Boolean?>>
+    private fun createPublicSpace(
+            session: Session,
+            spaceName: String,
+            childInfo: List<Triple<String, Boolean, Boolean?>>
             /** Name, auto-join, canonical*/
     ): TestSpaceCreationResult {
-        val commonTestHelper = CommonTestHelper(context())
         var spaceId = ""
         var roomIds: List<String> = emptyList()
-        commonTestHelper.waitWithLatch { latch ->
-            spaceId = session.spaceService().createSpace(spaceName, "Test Topic", null, true)
-            val syncedSpace = session.spaceService().getSpace(spaceId)
-            val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
-
-            roomIds = childInfo.map { entry ->
-                session.roomService().createRoom(CreateRoomParams().apply { name = entry.first })
-            }
-            roomIds.forEachIndexed { index, roomId ->
-                syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second)
-                val canonical = childInfo[index].third
-                if (canonical != null) {
-                    session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers)
+        runSessionTest(context()) { commonTestHelper ->
+            commonTestHelper.waitWithLatch { latch ->
+                spaceId = session.spaceService().createSpace(spaceName, "Test Topic", null, true)
+                val syncedSpace = session.spaceService().getSpace(spaceId)
+                val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
+
+                roomIds = childInfo.map { entry ->
+                    session.roomService().createRoom(CreateRoomParams().apply { name = entry.first })
+                }
+                roomIds.forEachIndexed { index, roomId ->
+                    syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second)
+                    val canonical = childInfo[index].third
+                    if (canonical != null) {
+                        session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers)
+                    }
                 }
+                latch.countDown()
             }
-            latch.countDown()
         }
         return TestSpaceCreationResult(spaceId, roomIds)
     }
 
-    private fun createPrivateSpace(session: Session,
-                                   spaceName: String,
-                                   childInfo: List<Triple<String, Boolean, Boolean?>>
+    private fun createPrivateSpace(
+            session: Session,
+            spaceName: String,
+            childInfo: List<Triple<String, Boolean, Boolean?>>
             /** Name, auto-join, canonical*/
     ): TestSpaceCreationResult {
-        val commonTestHelper = CommonTestHelper(context())
         var spaceId = ""
         var roomIds: List<String> = emptyList()
-        commonTestHelper.waitWithLatch { latch ->
-            spaceId = session.spaceService().createSpace(spaceName, "My Private Space", null, false)
-            val syncedSpace = session.spaceService().getSpace(spaceId)
-            val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
-            roomIds =
-                    childInfo.map { entry ->
-                        val homeServerCapabilities = session
-                                .homeServerCapabilitiesService()
-                                .getHomeServerCapabilities()
-                        session.roomService().createRoom(CreateRoomParams().apply {
-                            name = entry.first
-                            this.featurePreset = RestrictedRoomPreset(
-                                    homeServerCapabilities,
-                                    listOf(
-                                            RoomJoinRulesAllowEntry.restrictedToRoom(spaceId)
-                                    )
-                            )
-                        })
+        runSessionTest(context()) { commonTestHelper ->
+            commonTestHelper.waitWithLatch { latch ->
+                spaceId = session.spaceService().createSpace(spaceName, "My Private Space", null, false)
+                val syncedSpace = session.spaceService().getSpace(spaceId)
+                val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
+                roomIds =
+                        childInfo.map { entry ->
+                            val homeServerCapabilities = session
+                                    .homeServerCapabilitiesService()
+                                    .getHomeServerCapabilities()
+                            session.roomService().createRoom(CreateRoomParams().apply {
+                                name = entry.first
+                                this.featurePreset = RestrictedRoomPreset(
+                                        homeServerCapabilities,
+                                        listOf(
+                                                RoomJoinRulesAllowEntry.restrictedToRoom(spaceId)
+                                        )
+                                )
+                            })
+                        }
+                roomIds.forEachIndexed { index, roomId ->
+                    syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second)
+                    val canonical = childInfo[index].third
+                    if (canonical != null) {
+                        session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers)
                     }
-            roomIds.forEachIndexed { index, roomId ->
-                syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second)
-                val canonical = childInfo[index].third
-                if (canonical != null) {
-                    session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers)
                 }
+                latch.countDown()
             }
-            latch.countDown()
         }
         return TestSpaceCreationResult(spaceId, roomIds)
     }
 
     @Test
-    fun testRootSpaces() {
-        val commonTestHelper = CommonTestHelper(context())
+    fun testRootSpaces() = runSessionTest(context()) { commonTestHelper ->
         val session = commonTestHelper.createAccount("John", SessionTestParams(true))
 
         /* val spaceAInfo = */ createPublicSpace(
-                session, "SpaceA", listOf(
-                Triple("A1", true /*auto-join*/, true/*canonical*/),
-                Triple("A2", true, true)
-        )
-        )
+            session, "SpaceA", listOf(
+            Triple("A1", true /*auto-join*/, true/*canonical*/),
+            Triple("A2", true, true)
+    )
+    )
 
         val spaceBInfo = createPublicSpace(
                 session, "SpaceB", listOf(
@@ -506,13 +506,10 @@ class SpaceHierarchyTest : InstrumentedTest {
         }
 
         assertEquals("Unexpected number of root spaces ${rootSpaces.map { it.name }}", 2, rootSpaces.size)
-
-        commonTestHelper.signOutAndClose(session)
     }
 
     @Test
-    fun testParentRelation() {
-        val commonTestHelper = CommonTestHelper(context())
+    fun testParentRelation() = runSessionTest(context()) { commonTestHelper ->
         val aliceSession = commonTestHelper.createAccount("Alice", SessionTestParams(true))
         val bobSession = commonTestHelper.createAccount("Bib", SessionTestParams(true))
 
@@ -604,8 +601,5 @@ class SpaceHierarchyTest : InstrumentedTest {
                 bobSession.getRoomSummary(bobRoomId)?.flattenParentIds?.contains(spaceAInfo.spaceId) == true
             }
         }
-
-        commonTestHelper.signOutAndClose(aliceSession)
-        commonTestHelper.signOutAndClose(bobSession)
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt
index 3fe8d156962767af7871664bf24bd88baa5af343..556579942b9f1667c53769f003517a982761a869 100644
--- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt
+++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt
@@ -26,14 +26,14 @@ internal class InlineMaths(private val delimiter: InlineDelimiter) : CustomNode(
 
     override fun getOpeningDelimiter(): String {
         return when (delimiter) {
-            InlineDelimiter.SINGLE_DOLLAR         -> "$"
+            InlineDelimiter.SINGLE_DOLLAR -> "$"
             InlineDelimiter.ROUND_BRACKET_ESCAPED -> "\\("
         }
     }
 
     override fun getClosingDelimiter(): String {
         return when (delimiter) {
-            InlineDelimiter.SINGLE_DOLLAR         -> "$"
+            InlineDelimiter.SINGLE_DOLLAR -> "$"
             InlineDelimiter.ROUND_BRACKET_ESCAPED -> "\\)"
         }
     }
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 867e066e604f83195213c57cd781882a3e570432..82f39806c0392e6359496804106fede495ba17da 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
@@ -177,7 +177,7 @@ object MatrixPatterns {
      * - "@alice:domain.org".getDomain() will return "domain.org"
      * - "@bob:domain.org:3455".getDomain() will return "domain.org:3455"
      */
-    fun String.getDomain(): String {
+    fun String.getServerName(): String {
         if (BuildConfig.DEBUG && !isUserId(this)) {
             // They are some invalid userId localpart in the wild, but the domain part should be there anyway
             Timber.w("Not a valid user ID: $this")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/RoomDisplayNameFallbackProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/RoomDisplayNameFallbackProvider.kt
index a34dbcc1965a08741ed6d66bf0d2b8e61ca732f8..3c376b55ee15677a8169459d2e03777ad6479238 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/RoomDisplayNameFallbackProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/RoomDisplayNameFallbackProvider.kt
@@ -16,6 +16,14 @@
 
 package org.matrix.android.sdk.api
 
+/**
+ * This interface exists to let the implementation provide localized room display name fallback.
+ * The methods can be called when the room has no name, i.e. its `m.room.name` state event does not exist or
+ * the name in it is an empty String.
+ * It allows the SDK to store the room name fallback into the local storage and so let the client do
+ * queries on the room name.
+ * *Limitation*: if the locale of the device changes, the methods will not be called again.
+ */
 interface RoomDisplayNameFallbackProvider {
     fun getNameForRoomInvite(): String
     fun getNameForEmptyRoom(isDirect: Boolean, leftMemberNames: List<String>): String
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 5a19df90c4f99eb105f630241bc411ad541cdf1e..5ae70e1978c0e5bc9398560a12b81123b6a369ca 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
@@ -28,9 +28,11 @@ import org.matrix.android.sdk.api.session.Session
  * This interface defines methods to authenticate or to create an account to a matrix server.
  */
 interface AuthenticationService {
+
     /**
      * Request the supported login flows for this homeserver.
-     * This is the first method to call to be able to get a wizard to login or to create an account
+     * This is the first method to call to be able to get a wizard to login or to create an account.
+     * @param homeServerConnectionConfig contains the homeserver URL to login to, a wellKnown lookup will be attempted.
      */
     suspend fun getLoginFlow(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult
 
@@ -66,7 +68,7 @@ interface AuthenticationService {
     /**
      * True when login and password has been sent with success to the homeserver.
      */
-    val isRegistrationStarted: Boolean
+    fun isRegistrationStarted(): Boolean
 
     /**
      * Cancel pending login or pending registration.
@@ -93,14 +95,18 @@ interface AuthenticationService {
     /**
      * Create a session after a SSO successful login.
      */
-    suspend fun createSessionFromSso(homeServerConnectionConfig: HomeServerConnectionConfig,
-                                     credentials: Credentials): Session
+    suspend fun createSessionFromSso(
+            homeServerConnectionConfig: HomeServerConnectionConfig,
+            credentials: Credentials
+    ): Session
 
     /**
      * Perform a wellknown request, using the domain from the matrixId.
      */
-    suspend fun getWellKnownData(matrixId: String,
-                                 homeServerConnectionConfig: HomeServerConnectionConfig?): WellknownResult
+    suspend fun getWellKnownData(
+            matrixId: String,
+            homeServerConnectionConfig: HomeServerConnectionConfig?
+    ): WellknownResult
 
     /**
      * Authenticate with a matrixId and a password.
@@ -111,9 +117,11 @@ interface AuthenticationService {
      * @param initialDeviceName the initial device name
      * @param deviceId the device id, optional. If not provided or null, the server will generate one.
      */
-    suspend fun directAuthentication(homeServerConnectionConfig: HomeServerConnectionConfig,
-                                     matrixId: String,
-                                     password: String,
-                                     initialDeviceName: String,
-                                     deviceId: String? = null): Session
+    suspend fun directAuthentication(
+            homeServerConnectionConfig: HomeServerConnectionConfig,
+            matrixId: String,
+            password: String,
+            initialDeviceName: String,
+            deviceId: String? = null
+    ): Session
 }
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 80630bc4e7fbf7eafa3015b21bae6b07a6e8a955..e2f16ceee80217d1a7469da18e9ea3b7f1a46cc7 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
@@ -41,8 +41,10 @@ import org.matrix.android.sdk.api.auth.registration.TermPolicies
  * @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> {
+fun TermPolicies.toLocalizedLoginTerms(
+        userLanguage: String,
+        defaultLanguage: String = "en"
+): List<LocalizedFlowDataLoginTerms> {
     val result = ArrayList<LocalizedFlowDataLoginTerms>()
 
     val policies = get("policies")
@@ -67,8 +69,8 @@ fun TermPolicies.toLocalizedLoginTerms(userLanguage: String,
                 // Search for language
                 policy.keys.forEach { policyKey ->
                     when (policyKey) {
-                        "version"       -> Unit // Ignore
-                        userLanguage    -> {
+                        "version" -> Unit // Ignore
+                        userLanguage -> {
                             // We found the data for the user language
                             userLanguageUrlAndName = extractUrlAndName(policy[policyKey])
                         }
@@ -76,7 +78,7 @@ fun TermPolicies.toLocalizedLoginTerms(userLanguage: String,
                             // We found default language
                             defaultLanguageUrlAndName = extractUrlAndName(policy[policyKey])
                         }
-                        else            -> {
+                        else -> {
                             if (firstUrlAndName == null) {
                                 // Get at least some data
                                 firstUrlAndName = extractUrlAndName(policy[policyKey])
@@ -87,7 +89,7 @@ fun TermPolicies.toLocalizedLoginTerms(userLanguage: String,
 
                 // Copy found language data by priority
                 when {
-                    userLanguageUrlAndName != null    -> {
+                    userLanguageUrlAndName != null -> {
                         localizedFlowDataLoginTermsLocalizedUrl = userLanguageUrlAndName!!.url
                         localizedFlowDataLoginTermsLocalizedName = userLanguageUrlAndName!!.name
                     }
@@ -95,7 +97,7 @@ fun TermPolicies.toLocalizedLoginTerms(userLanguage: String,
                         localizedFlowDataLoginTermsLocalizedUrl = defaultLanguageUrlAndName!!.url
                         localizedFlowDataLoginTermsLocalizedName = defaultLanguageUrlAndName!!.name
                     }
-                    firstUrlAndName != null           -> {
+                    firstUrlAndName != null -> {
                         localizedFlowDataLoginTermsLocalizedUrl = firstUrlAndName!!.url
                         localizedFlowDataLoginTermsLocalizedName = firstUrlAndName!!.name
                     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt
index c2c1f043bbf4aa3b4ec69ebe46b2511fd0ab36fd..c3f0221bb896242efb6ab7578d6f8c12767e20ca 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt
@@ -195,7 +195,7 @@ data class HomeServerConnectionConfig(
          * - https://www.ssi.gouv.fr/uploads/2017/07/anssi-guide-recommandations_de_securite_relatives_a_tls-v1.2.pdf
          * - https://developer.android.com/reference/javax/net/ssl/SSLEngine
          *
-         * @param tlsLimitations         true to use Tls limitations
+         * @param tlsLimitations true to use Tls limitations
          * @param enableCompatibilityMode set to true for Android < 20
          * @return this builder
          */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt
index a0733dda978263754d95b6b841864e356908243a..773f5a8cc4b0878f6f7d00d1614081ad74491e42 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt
@@ -66,17 +66,17 @@ data class SsoIdentityProvider(
     private fun toPriority(): Int {
         return when (brand) {
             // We are on Android, so user is more likely to have a Google account
-            BRAND_GOOGLE   -> 5
+            BRAND_GOOGLE -> 5
             // Facebook is also an important SSO provider
             BRAND_FACEBOOK -> 4
             // Twitter is more for professionals
-            BRAND_TWITTER  -> 3
+            BRAND_TWITTER -> 3
             // Here it's very for techie people
             BRAND_GITHUB,
-            BRAND_GITLAB   -> 2
+            BRAND_GITLAB -> 2
             // And finally, if the account has been created with an iPhone...
-            BRAND_APPLE    -> 1
-            else           -> 0
+            BRAND_APPLE -> 1
+            else -> 0
         }
     }
 }
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 3232025de39a0c3c2271a7dbc34ed66e8466309a..5b8d2328c769ef3c49d192eac13c232e4226bd56 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
@@ -39,10 +39,12 @@ interface LoginWizard {
      * @param deviceId the device id, optional. If not provided or null, the server will generate one.
      * @return a [Session] if the login is successful
      */
-    suspend fun login(login: String,
-                      password: String,
-                      initialDeviceName: String,
-                      deviceId: String? = null): Session
+    suspend fun login(
+            login: String,
+            password: String,
+            initialDeviceName: String,
+            deviceId: String? = null
+    ): Session
 
     /**
      * Exchange a login token to an access token.
@@ -63,14 +65,14 @@ interface LoginWizard {
      * [resetPasswordMailConfirmed] is successfully called.
      *
      * @param email an email previously associated to the account the user wants the password to be reset.
-     * @param newPassword the desired new password
      */
-    suspend fun resetPassword(email: String,
-                              newPassword: String)
+    suspend fun resetPassword(email: String)
 
     /**
      * Confirm the new password, once the user has checked their email
      * When this method succeed, tha account password will be effectively modified.
+     *
+     * @param newPassword the desired new password
      */
-    suspend fun resetPasswordMailConfirmed()
+    suspend fun resetPasswordMailConfirmed(newPassword: String)
 }
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 1252e93b84848d72b678977b269e37a73b603b9e..98542d208650aa682b033582d05627ecc7bf8009 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
@@ -88,15 +88,15 @@ fun RegistrationFlowResponse.toFlowResult(): FlowResult {
         val isMandatory = flows?.all { type in it.stages.orEmpty() } == true
 
         val stage = when (type) {
-            LoginFlowTypes.RECAPTCHA      -> Stage.ReCaptcha(
+            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.DUMMY -> Stage.Dummy(isMandatory)
+            LoginFlowTypes.TERMS -> Stage.Terms(isMandatory, params?.get(type) as? TermPolicies ?: emptyMap<String, String>())
             LoginFlowTypes.EMAIL_IDENTITY -> Stage.Email(isMandatory)
-            LoginFlowTypes.MSISDN         -> Stage.Msisdn(isMandatory)
-            else                          -> Stage.Other(isMandatory, type, (params?.get(type) as? Map<*, *>))
+            LoginFlowTypes.MSISDN -> Stage.Msisdn(isMandatory)
+            else -> Stage.Other(isMandatory, type, (params?.get(type) as? Map<*, *>))
         }
 
         if (type in completedStages.orEmpty()) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationResult.kt
index 439b4beb4169bc1e8ed955edc7c57899b4ba3bd4..9e6b2b3ad91cbd3966ca85550b33637e49641b54 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationResult.kt
@@ -18,13 +18,31 @@ package org.matrix.android.sdk.api.auth.registration
 
 import org.matrix.android.sdk.api.session.Session
 
-// Either a session or an object containing data about registration stages
+/**
+ * Either a session or an object containing data about registration stages.
+ */
 sealed class RegistrationResult {
+    /**
+     * The registration is successful, the [Session] is provided.
+     */
     data class Success(val session: Session) : RegistrationResult()
+
+    /**
+     * The registration still miss some steps. See [FlowResult] to know the details.
+     */
     data class FlowResponse(val flowResult: FlowResult) : RegistrationResult()
 }
 
+/**
+ * Information about the missing and completed [Stage].
+ */
 data class FlowResult(
+        /**
+         * List of missing stages.
+         */
         val missingStages: List<Stage>,
+        /**
+         * List of completed stages.
+         */
         val completedStages: List<Stage>
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt
index 0cda64499f126def2d5d006c0b1b1bca80661199..995fd27acecfd2241b099b4f9c5e4e502feb2ddf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt
@@ -54,9 +54,11 @@ interface RegistrationWizard {
      * @param password the desired password
      * @param initialDeviceDisplayName the device display name
      */
-    suspend fun createAccount(userName: String?,
-                              password: String?,
-                              initialDeviceDisplayName: String?): RegistrationResult
+    suspend fun createAccount(
+            userName: String?,
+            password: String?,
+            initialDeviceDisplayName: String?
+    ): RegistrationResult
 
     /**
      * Perform the "m.login.recaptcha" stage.
@@ -109,14 +111,14 @@ interface RegistrationWizard {
     suspend fun checkIfEmailHasBeenValidated(delayMillis: Long): RegistrationResult
 
     /**
-     * This is the current ThreePid, waiting for validation. The SDK will store it in database, so it can be
+     * Returns the current ThreePid, waiting for validation. The SDK will store it in database, so it can be
      * restored even if the app has been killed during the registration
      */
-    val currentThreePid: String?
+    fun getCurrentThreePid(): String?
 
     /**
-     * True when login and password have been sent with success to the homeserver, i.e. [createAccount] has been
+     * Return true when login and password have been sent with success to the homeserver, i.e. [createAccount] has been
      * called successfully.
      */
-    val isRegistrationStarted: Boolean
+    fun isRegistrationStarted(): Boolean
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/Stage.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/Stage.kt
index c21b667cf7f6817292ba3eee9a959267894eff00..281b0c28081c07f9e7ae00f4e19314f528eda3ef 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/Stage.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/Stage.kt
@@ -16,25 +16,40 @@
 
 package org.matrix.android.sdk.api.auth.registration
 
+/**
+ * Registration stages.
+ */
 sealed class Stage(open val mandatory: Boolean) {
 
-    // m.login.recaptcha
+    /**
+     * m.login.recaptcha stage.
+     */
     data class ReCaptcha(override val mandatory: Boolean, val publicKey: String) : Stage(mandatory)
 
-    // m.login.email.identity
+    /**
+     * m.login.email.identity stage.
+     */
     data class Email(override val mandatory: Boolean) : Stage(mandatory)
 
-    // m.login.msisdn
+    /**
+     * m.login.msisdn stage.
+     */
     data class Msisdn(override val mandatory: Boolean) : Stage(mandatory)
 
-    // m.login.dummy, can be mandatory if there is no other stages. In this case the account cannot be created by just sending a username
-    // and a password, the dummy stage has to be done
+    /**
+     * m.login.dummy, can be mandatory if there is no other stages. In this case the account cannot be created by just sending a username
+     * and a password, the dummy stage has to be done.
+     */
     data class Dummy(override val mandatory: Boolean) : Stage(mandatory)
 
-    // Undocumented yet: m.login.terms
+    /**
+     * Undocumented yet: m.login.terms stage.
+     */
     data class Terms(override val mandatory: Boolean, val policies: TermPolicies) : Stage(mandatory)
 
-    // For unknown stages
+    /**
+     * For unknown stages.
+     */
     data class Other(override val mandatory: Boolean, val type: String, val params: Map<*, *>?) : Stage(mandatory)
 }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt
index 56257db79c42f2438639bed8eb0dd0cc36fe97b3..ea5570db1cda325ec3247bdd949ce4f93166fbbb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt
@@ -26,9 +26,11 @@ sealed class WellknownResult {
      * Retrieve the specific piece of information from the user in a way which fits within the existing client user experience,
      * if the client is inclined to do so. Failure can take place instead if no good user experience for this is possible at this point.
      */
-    data class Prompt(val homeServerUrl: String,
-                      val identityServerUrl: String?,
-                      val wellKnown: WellKnown) : WellknownResult()
+    data class Prompt(
+            val homeServerUrl: String,
+            val identityServerUrl: String?,
+            val wellKnown: WellKnown
+    ) : WellknownResult()
 
     /**
      * Stop the current auto-discovery mechanism. If no more auto-discovery mechanisms are available,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/cache/CacheStrategy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/cache/CacheStrategy.kt
index 2880d851d6c2070d63b1cbd6b4dd4bf85031c73f..ddf76d6e42372b7dd07035290a2c9771d740bfa5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/cache/CacheStrategy.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/cache/CacheStrategy.kt
@@ -17,13 +17,19 @@
 package org.matrix.android.sdk.api.cache
 
 sealed class CacheStrategy {
-    // Data is always fetched from the server
+    /**
+     * Data is always fetched from the server.
+     */
     object NoCache : CacheStrategy()
 
-    // Once data is retrieved, it is stored for the provided amount of time.
-    // In case of error, and if strict is set to false, the cache can be returned if available
+    /**
+     * Once data is retrieved, it is stored for the provided amount of time.
+     * In case of error, and if strict is set to false, the cache can be returned if available
+     */
     data class TtlCache(val validityDurationInMillis: Long, val strict: Boolean) : CacheStrategy()
 
-    // Once retrieved, the data is stored in cache and will be always get from the cache
+    /**
+     * Once retrieved, the data is stored in cache and will be always get from the cache.
+     */
     object InfiniteCache : CacheStrategy()
 }
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 5e1350e32791ac60019659e3356511fc3b353708..9f979098f8e0c24b5fe12de68e6425f827732b7c 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
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.extensions
 fun CharSequence.ensurePrefix(prefix: CharSequence): CharSequence {
     return when {
         startsWith(prefix) -> this
-        else               -> "$prefix$this"
+        else -> "$prefix$this"
     }
 }
 
@@ -27,3 +27,8 @@ fun CharSequence.ensurePrefix(prefix: CharSequence): CharSequence {
  * Append a new line and then the provided string.
  */
 fun StringBuilder.appendNl(str: String) = append("\n").append(str)
+
+/**
+ * Returns null if the string is empty.
+ */
+fun String.ensureNotEmpty() = ifEmpty { null }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt
index be139fd82bd44c8c61e0182256d4962e63f449f5..7d4f553bede46b57f736d154a2ce32f37f521ad1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt
@@ -37,7 +37,9 @@ sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) {
     data class ServerError(val error: MatrixError, val httpCode: Int) : Failure(RuntimeException(error.toString()))
     object SuccessError : Failure(RuntimeException(RuntimeException("SuccessResult is false")))
 
-    // When server send an error, but it cannot be interpreted as a MatrixError
+    /**
+     * When server send an error, but it cannot be interpreted as a MatrixError.
+     */
     data class OtherServerError(val errorBody: String, val httpCode: Int) : Failure(RuntimeException("HTTP $httpCode: $errorBody"))
 
     data class RegistrationFlowError(val registrationFlowResponse: RegistrationFlowResponse) : Failure(RuntimeException(registrationFlowResponse.toString()))
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ssl/Fingerprint.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ssl/Fingerprint.kt
index 93e93fd292115bef726b53d7efa9f0ca0f8e7c62..2fc04013f9e6198c921788e0daabb7adb8f3e92c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ssl/Fingerprint.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ssl/Fingerprint.kt
@@ -36,7 +36,7 @@ data class Fingerprint(
     internal fun matchesCert(cert: X509Certificate): Boolean {
         val o: Fingerprint? = when (hashType) {
             HashType.SHA256 -> newSha256Fingerprint(cert)
-            HashType.SHA1   -> newSha1Fingerprint(cert)
+            HashType.SHA1 -> newSha1Fingerprint(cert)
         }
         return equals(o)
     }
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 368ff986613783037cd0b44771d9d8ebdfb9fdcd..f08c86885d7e2179e40d26fe10d437e82ee2f772 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
@@ -20,20 +20,52 @@ package org.matrix.android.sdk.api.query
  * Basic query language. All these cases are mutually exclusive.
  */
 sealed interface QueryStringValue {
-    sealed interface ContentQueryStringValue : QueryStringValue {
-        val string: String
-        val case: Case
-    }
-
+    /**
+     * No condition, i.e. there will be no test on the tested field.
+     */
     object NoCondition : QueryStringValue
+
+    /**
+     * The tested field has to be null.
+     */
     object IsNull : QueryStringValue
+
+    /**
+     * The tested field has to be not null.
+     */
     object IsNotNull : QueryStringValue
+
+    /**
+     * The tested field has to be empty.
+     */
     object IsEmpty : QueryStringValue
+
+    /**
+     * The tested field has to not empty.
+     */
     object IsNotEmpty : QueryStringValue
 
+    /**
+     * Interface to check String content.
+     */
+    sealed interface ContentQueryStringValue : QueryStringValue {
+        val string: String
+        val case: Case
+    }
+
+    /**
+     * The tested field must match the [string].
+     */
     data class Equals(override val string: String, override val case: Case = Case.SENSITIVE) : ContentQueryStringValue
+
+    /**
+     * The tested field must contain the [string].
+     */
     data class Contains(override val string: String, override val case: Case = Case.SENSITIVE) : ContentQueryStringValue
 
+    /**
+     * Case enum for [ContentQueryStringValue].
+     */
     enum class Case {
         /**
          * Match query sensitive to case.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomCategoryFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomCategoryFilter.kt
index c8ccc4c8a3ec3d8e9abce5ffee7591675028120f..c2117adbd356caa35471548ca8ec43c78b469e99 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomCategoryFilter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomCategoryFilter.kt
@@ -16,9 +16,23 @@
 
 package org.matrix.android.sdk.api.query
 
+/**
+ * To filter by Room category.
+ * @see [org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams]
+ */
 enum class RoomCategoryFilter {
+    /**
+     * Get only the DM, i.e. the rooms referenced in `m.direct` account data.
+     */
     ONLY_DM,
+
+    /**
+     * Get only the Room, not the DM, i.e. the rooms not referenced in `m.direct` account data.
+     */
     ONLY_ROOMS,
+
+    /**
+     * Get the room with non-0 notifications.
+     */
     ONLY_WITH_NOTIFICATIONS,
-    ALL
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomTagQueryFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomTagQueryFilter.kt
index 613916bc18a3a4b0d569595bc7a444a40bde45c7..73947f8f7a6e10c9c40b30a2848643cbbcfc9622 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomTagQueryFilter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomTagQueryFilter.kt
@@ -16,8 +16,22 @@
 
 package org.matrix.android.sdk.api.query
 
+/**
+ * Filter room by their tag.
+ * @see [org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams]
+ * @see [org.matrix.android.sdk.api.session.room.model.tag.RoomTag]
+ */
 data class RoomTagQueryFilter(
+        /**
+         * Set to true to get the rooms which have the tag "m.favourite".
+         */
         val isFavorite: Boolean?,
+        /**
+         * Set to true to get the rooms which have the tag "m.lowpriority".
+         */
         val isLowPriority: Boolean?,
-        val isServerNotice: Boolean?
+        /**
+         * Set to true to get the rooms which have the tag "m.server_notice".
+         */
+        val isServerNotice: Boolean?,
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/SpaceFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/SpaceFilter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6383412ffbdf714fa4b2ad8d8391508fc28b223f
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/SpaceFilter.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021 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.query
+
+/**
+ * Filter to be used to do room queries regarding the space hierarchy.
+ * @see [org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams]
+ */
+sealed interface SpaceFilter {
+    /**
+     * Used to get all the rooms that are not in any space.
+     */
+    object OrphanRooms : SpaceFilter
+
+    /**
+     * Used to get all the rooms that have the provided space in their parent hierarchy.
+     */
+    data class ActiveSpace(val spaceId: String) : SpaceFilter
+
+    /**
+     * Used to get all the rooms that do not have the provided space in their parent hierarchy.
+     */
+    data class ExcludeSpace(val spaceId: String) : SpaceFilter
+}
+
+/**
+ * Return a [SpaceFilter.ActiveSpace] if the String is not null, or [SpaceFilter.OrphanRooms].
+ */
+fun String?.toActiveSpaceOrOrphanRooms(): SpaceFilter = this?.let { SpaceFilter.ActiveSpace(it) } ?: SpaceFilter.OrphanRooms
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 2f1ae8cd87626fe744434bdecd911d40c5118312..b3a629094cb20d79a751600b795c69c8ed6638a1 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
@@ -17,8 +17,6 @@
 package org.matrix.android.sdk.api.session
 
 import androidx.annotation.MainThread
-import androidx.lifecycle.LiveData
-import kotlinx.coroutines.flow.SharedFlow
 import okhttp3.OkHttpClient
 import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
 import org.matrix.android.sdk.api.auth.data.SessionParams
@@ -37,7 +35,6 @@ import org.matrix.android.sdk.api.session.file.FileService
 import org.matrix.android.sdk.api.session.group.GroupService
 import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
 import org.matrix.android.sdk.api.session.identity.IdentityService
-import org.matrix.android.sdk.api.session.initsync.SyncStatusService
 import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
 import org.matrix.android.sdk.api.session.media.MediaService
 import org.matrix.android.sdk.api.session.openid.OpenIdService
@@ -55,8 +52,7 @@ import org.matrix.android.sdk.api.session.signout.SignOutService
 import org.matrix.android.sdk.api.session.space.SpaceService
 import org.matrix.android.sdk.api.session.statistics.StatisticsListener
 import org.matrix.android.sdk.api.session.sync.FilterService
-import org.matrix.android.sdk.api.session.sync.SyncState
-import org.matrix.android.sdk.api.session.sync.model.SyncResponse
+import org.matrix.android.sdk.api.session.sync.SyncService
 import org.matrix.android.sdk.api.session.terms.TermsService
 import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
 import org.matrix.android.sdk.api.session.typing.TypingUsersTracker
@@ -98,59 +94,11 @@ interface Session {
     @MainThread
     fun open()
 
-    /**
-     * Requires a one time background sync.
-     */
-    fun requireBackgroundSync()
-
-    /**
-     * Launches infinite self rescheduling background syncs via the WorkManager.
-     *
-     * 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.
-     */
-    fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long)
-
-    fun stopAnyBackgroundSync()
-
-    /**
-     * This method start the sync thread.
-     */
-    fun startSync(fromForeground: Boolean)
-
-    /**
-     * This method stop the sync thread.
-     */
-    fun stopSync()
-
     /**
      * Clear cache of the session.
      */
     suspend fun clearCache()
 
-    /**
-     * This method allows to listen the sync state.
-     * @return a [LiveData] of [SyncState].
-     */
-    fun getSyncStateLive(): LiveData<SyncState>
-
-    /**
-     * This method returns the current sync state.
-     * @return the current [SyncState].
-     */
-    fun getSyncState(): SyncState
-
-    /**
-     * This method returns a flow of SyncResponse. New value will be pushed through the sync thread.
-     */
-    fun syncFlow(): SharedFlow<SyncResponse>
-
-    /**
-     * This methods return true if an initial sync has been processed.
-     */
-    fun hasAlreadySynced(): Boolean
-
     /**
      * This method allow to close a session. It does stop some services.
      */
@@ -247,9 +195,9 @@ interface Session {
     fun termsService(): TermsService
 
     /**
-     * Returns the SyncStatusService associated with the session.
+     * Returns the SyncService associated with the session.
      */
-    fun syncStatusService(): SyncStatusService
+    fun syncService(): SyncService
 
     /**
      * Returns the SecureStorageService associated with the session.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt
index 1f28dbd8afbef2c21b0e9aaee1d080c44b4ae3a9..e3d52adfc58da34c9825536ebeaab226e5ea32a0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt
@@ -27,8 +27,10 @@ interface AccountService {
      * @param password Current password.
      * @param newPassword New password
      */
-    suspend fun changePassword(password: String,
-                               newPassword: String)
+    suspend fun changePassword(
+            password: String,
+            newPassword: String
+    )
 
     /**
      * Deactivate the account.
@@ -46,6 +48,8 @@ interface AccountService {
      * an incomplete view of conversations
      * @param userInteractiveAuthInterceptor see [UserInteractiveAuthInterceptor]
      */
-    suspend fun deactivateAccount(eraseAllData: Boolean,
-                                  userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor)
+    suspend fun deactivateAccount(
+            eraseAllData: Boolean,
+            userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor
+    )
 }
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 e13f7310e05696cecfa81c396f8357a5266d67ec..c87ac3c8218cdebab5928d9cf0ecc3613ea6eef2 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
@@ -91,10 +91,12 @@ interface MxCall : MxCallDetail {
      * Send a m.call.replaces event to initiate call transfer.
      * See [org.matrix.android.sdk.api.session.room.model.call.CallReplacesContent] for documentation about the parameters
      */
-    suspend fun transfer(targetUserId: String,
-                         targetRoomId: String?,
-                         createCallId: String?,
-                         awaitCallId: String?)
+    suspend fun transfer(
+            targetUserId: String,
+            targetRoomId: String?,
+            createCallId: String?,
+            awaitCallId: String?
+    )
 
     fun addListener(listener: StateListener)
     fun removeListener(listener: StateListener)
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 e59e676ed9587f2670bbce0db540e7e5011a34ad..20f977e86e90bfd0293661076a268d722a960478 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
@@ -36,7 +36,7 @@ interface ContentUrlResolver {
     /**
      * Get the actual URL for accessing the full-size image of a Matrix media content URI.
      *
-     * @param contentUrl  the Matrix media content URI (in the form of "mxc://...").
+     * @param contentUrl the Matrix media content URI (in the form of "mxc://...").
      * @return the URL to access the described resource, or null if the url is invalid.
      */
     fun resolveFullSize(contentUrl: String?): String?
@@ -44,7 +44,7 @@ interface ContentUrlResolver {
     /**
      * Get the ResolvedMethod to download a URL.
      *
-     * @param contentUrl  the Matrix media content URI (in the form of "mxc://...").
+     * @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
      * @return the Method to access resource, or null if invalid
      */
@@ -54,9 +54,9 @@ interface ContentUrlResolver {
      * Get the actual URL for accessing the thumbnail image of a given Matrix media content URI.
      *
      * @param contentUrl the Matrix media content URI (in the form of "mxc://...").
-     * @param width      the desired width
-     * @param height     the desired height
-     * @param method     the desired method (METHOD_CROP or METHOD_SCALE)
+     * @param width the desired width
+     * @param height the desired height
+     * @param method the desired method (METHOD_CROP or METHOD_SCALE)
      * @return the URL to access the described resource, or null if the url is invalid.
      */
     fun resolveThumbnail(contentUrl: String?, width: Int, height: Int, method: ThumbnailMethod): String?
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerService.kt
index 7a85a89058a8ad011b4c68cea1248f2d7eaa1b34..22250628d5579dc7a7737b5dad4ec85577d27fa2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerService.kt
@@ -33,7 +33,7 @@ interface ContentScannerService {
 
     /**
      * Get the current public curve25519 key that the AV server is advertising.
-     * @param callback on success callback containing the server public key
+     * @param forceDownload true to force the SDK to download again the server public key
      */
     suspend fun getServerPublicKey(forceDownload: Boolean = false): String?
     suspend fun getScanResultForAttachment(mxcUrl: String, fileInfo: ElementToDecrypt? = null): ScanStatusInfo
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 35f3ab3162466745fb6c09ec19e33368d392cbf6..9cc87b6f718476c8b0ea5ee530926e9507688427 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
@@ -88,9 +88,11 @@ interface CryptoService {
 
     fun getDeviceTrackingStatus(userId: String): Int
 
-    suspend fun importRoomKeys(roomKeysAsArray: ByteArray,
-                               password: String,
-                               progressListener: ProgressListener?): ImportRoomKeysResult
+    suspend fun importRoomKeys(
+            roomKeysAsArray: ByteArray,
+            password: String,
+            progressListener: ProgressListener?
+    ): ImportRoomKeysResult
 
     suspend fun exportRoomKeys(password: String): ByteArray
 
@@ -119,10 +121,12 @@ interface CryptoService {
     fun isRoomEncrypted(roomId: String): Boolean
 
     // TODO This could be removed from this interface
-    fun encryptEventContent(eventContent: Content,
-                            eventType: String,
-                            roomId: String,
-                            callback: MatrixCallback<MXEncryptEventContentResult>)
+    fun encryptEventContent(
+            eventContent: Content,
+            eventType: String,
+            roomId: String,
+            callback: MatrixCallback<MXEncryptEventContentResult>
+    )
 
     fun discardOutboundSession(roomId: String)
 
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 0b5bbe3bbdb5f38e6fd818b5490e6b8850825b6d..94ee7ba403e06b15aa9e3b9a90b10681b98d816c 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
@@ -25,12 +25,14 @@ import org.matrix.olm.OlmException
  */
 sealed class MXCryptoError : Throwable() {
 
-    data class Base(val errorType: ErrorType,
-                    val technicalMessage: String,
-                    /**
-                     * Describe the error with more details.
-                     */
-                    val detailedErrorDescription: String? = null) : MXCryptoError()
+    data class Base(
+            val errorType: ErrorType,
+            val technicalMessage: String,
+            /**
+             * Describe the error with more details.
+             */
+            val detailedErrorDescription: String? = null
+    ) : MXCryptoError()
 
     data class OlmError(val olmException: OlmException) : MXCryptoError()
 
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
index 855f17a34fff1d165893a2e92db43555a1d2f52f..7202be7a214bf42f1c3a91e6ca6f472e77f01609 100644
--- 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
@@ -26,7 +26,7 @@ data class RequestReply(
 )
 
 sealed class RequestResult {
-    data class  Success(val chainIndex: Int) : RequestResult()
+    data class Success(val chainIndex: Int) : RequestResult()
     data class Failure(val code: WithHeldCode) : RequestResult()
 }
 
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 5439389096bbd3cb6210f2c89d0509cd83562c05..69f314f76f435a84f9bd035414a4a607910758ad 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
@@ -37,14 +37,18 @@ interface CrossSigningService {
      * Initialize cross signing for this user.
      * Users needs to enter credentials
      */
-    fun initializeCrossSigning(uiaInterceptor: UserInteractiveAuthInterceptor?,
-                               callback: MatrixCallback<Unit>)
+    fun initializeCrossSigning(
+            uiaInterceptor: UserInteractiveAuthInterceptor?,
+            callback: MatrixCallback<Unit>
+    )
 
     fun isCrossSigningInitialized(): Boolean = getMyCrossSigningKeys() != null
 
-    fun checkTrustFromPrivateKeys(masterKeyPrivateKey: String?,
-                                  uskKeyPrivateKey: String?,
-                                  sskPrivateKey: String?): UserTrustResult
+    fun checkTrustFromPrivateKeys(
+            masterKeyPrivateKey: String?,
+            uskKeyPrivateKey: String?,
+            sskPrivateKey: String?
+    ): UserTrustResult
 
     fun getUserCrossSigningKeys(otherUserId: String): MXCrossSigningInfo?
 
@@ -60,20 +64,26 @@ interface CrossSigningService {
 
     fun allPrivateKeysKnown(): Boolean
 
-    fun trustUser(otherUserId: String,
-                  callback: MatrixCallback<Unit>)
+    fun trustUser(
+            otherUserId: String,
+            callback: MatrixCallback<Unit>
+    )
 
     fun markMyMasterKeyAsTrusted()
 
     /**
      * Sign one of your devices and upload the signature.
      */
-    fun trustDevice(deviceId: String,
-                    callback: MatrixCallback<Unit>)
-
-    fun checkDeviceTrust(otherUserId: String,
-                         otherDeviceId: String,
-                         locallyTrusted: Boolean?): DeviceTrustResult
+    fun trustDevice(
+            deviceId: String,
+            callback: MatrixCallback<Unit>
+    )
+
+    fun checkDeviceTrust(
+            otherUserId: String,
+            otherDeviceId: String,
+            locallyTrusted: Boolean?
+    ): DeviceTrustResult
 
     // FIXME Those method do not have to be in the service
     fun onSecretMSKGossip(mskPrivateKey: String)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupLastVersionResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupLastVersionResult.kt
index a7e985cea9764cdf5b72696e8861d42b67c3b79c..92510bb52e50ae3de24fa9085b85be5be897c04d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupLastVersionResult.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupLastVersionResult.kt
@@ -24,5 +24,5 @@ sealed interface KeysBackupLastVersionResult {
 
 fun KeysBackupLastVersionResult.toKeysVersionResult(): KeysVersionResult? = when (this) {
     is KeysBackupLastVersionResult.KeysBackup -> keysVersionResult
-    KeysBackupLastVersionResult.NoKeysBackup  -> null
+    KeysBackupLastVersionResult.NoKeysBackup -> null
 }
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 0d40490c3e6858a290d21c0937d828cb687ce1b1..8745003f9f59ae67574587535c340b9bf0847084 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
@@ -34,10 +34,12 @@ interface KeysBackupService {
      * Create a new keys backup version and enable it, using the information return from [prepareKeysBackupVersion].
      *
      * @param keysBackupCreationInfo the info object from [prepareKeysBackupVersion].
-     * @param callback               Asynchronous callback
+     * @param callback Asynchronous callback
      */
-    fun createKeysBackupVersion(keysBackupCreationInfo: MegolmBackupCreationInfo,
-                                callback: MatrixCallback<KeysVersion>)
+    fun createKeysBackupVersion(
+            keysBackupCreationInfo: MegolmBackupCreationInfo,
+            callback: MatrixCallback<KeysVersion>
+    )
 
     /**
      * Facility method to get the total number of locally stored keys.
@@ -55,8 +57,10 @@ interface KeysBackupService {
      * @param progressListener the callback to follow the progress
      * @param callback the main callback
      */
-    fun backupAllGroupSessions(progressListener: ProgressListener?,
-                               callback: MatrixCallback<Unit>?)
+    fun backupAllGroupSessions(
+            progressListener: ProgressListener?,
+            callback: MatrixCallback<Unit>?
+    )
 
     /**
      * Check trust on a key backup version.
@@ -64,8 +68,10 @@ interface KeysBackupService {
      * @param keysBackupVersion the backup version to check.
      * @param callback block called when the operations completes.
      */
-    fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult,
-                           callback: MatrixCallback<KeysBackupVersionTrust>)
+    fun getKeysBackupTrust(
+            keysBackupVersion: KeysVersionResult,
+            callback: MatrixCallback<KeysBackupVersionTrust>
+    )
 
     /**
      * Return the current progress of the backup.
@@ -79,8 +85,10 @@ interface KeysBackupService {
      * @param version the backup version
      * @param callback
      */
-    fun getVersion(version: String,
-                   callback: MatrixCallback<KeysVersionResult?>)
+    fun getVersion(
+            version: String,
+            callback: MatrixCallback<KeysVersionResult?>
+    )
 
     /**
      * This method fetches the last backup version on the server, then compare to the currently backup version use.
@@ -114,19 +122,23 @@ interface KeysBackupService {
      * @param progressListener a progress listener, as generating private key from password may take a while
      * @param callback Asynchronous callback
      */
-    fun prepareKeysBackupVersion(password: String?,
-                                 progressListener: ProgressListener?,
-                                 callback: MatrixCallback<MegolmBackupCreationInfo>)
+    fun prepareKeysBackupVersion(
+            password: String?,
+            progressListener: ProgressListener?,
+            callback: MatrixCallback<MegolmBackupCreationInfo>
+    )
 
     /**
      * Delete a keys backup version. It will delete all backed up keys on the server, and the backup itself.
      * If we are backing up to this version. Backup will be stopped.
      *
-     * @param version  the backup version to delete.
+     * @param version the backup version to delete.
      * @param callback Asynchronous callback
      */
-    fun deleteBackup(version: String,
-                     callback: MatrixCallback<Unit>?)
+    fun deleteBackup(
+            version: String,
+            callback: MatrixCallback<Unit>?
+    )
 
     /**
      * Ask if the backup on the server contains keys that we may do not have locally.
@@ -142,9 +154,11 @@ interface KeysBackupService {
      * @param trust the trust to set to the keys backup.
      * @param callback block called when the operations completes.
      */
-    fun trustKeysBackupVersion(keysBackupVersion: KeysVersionResult,
-                               trust: Boolean,
-                               callback: MatrixCallback<Unit>)
+    fun trustKeysBackupVersion(
+            keysBackupVersion: KeysVersionResult,
+            trust: Boolean,
+            callback: MatrixCallback<Unit>
+    )
 
     /**
      * Set trust on a keys backup version.
@@ -153,9 +167,11 @@ interface KeysBackupService {
      * @param recoveryKey the recovery key to challenge with the key backup public key.
      * @param callback block called when the operations completes.
      */
-    fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult,
-                                              recoveryKey: String,
-                                              callback: MatrixCallback<Unit>)
+    fun trustKeysBackupVersionWithRecoveryKey(
+            keysBackupVersion: KeysVersionResult,
+            recoveryKey: String,
+            callback: MatrixCallback<Unit>
+    )
 
     /**
      * Set trust on a keys backup version.
@@ -164,27 +180,30 @@ interface KeysBackupService {
      * @param password the pass phrase to challenge with the keyBackupVersion public key.
      * @param callback block called when the operations completes.
      */
-    fun trustKeysBackupVersionWithPassphrase(keysBackupVersion: KeysVersionResult,
-                                             password: String,
-                                             callback: MatrixCallback<Unit>)
-
-    fun onSecretKeyGossip(secret: String)
+    fun trustKeysBackupVersionWithPassphrase(
+            keysBackupVersion: KeysVersionResult,
+            password: String,
+            callback: MatrixCallback<Unit>
+    )
 
     /**
      * Restore a backup with a recovery key from a given backup version stored on the homeserver.
      *
-     * @param keysVersionResult    the backup version to restore from.
-     * @param recoveryKey          the recovery key to decrypt the retrieved backup.
-     * @param roomId               the id of the room to get backup data from.
-     * @param sessionId            the id of the session to restore.
+     * @param keysVersionResult the backup version to restore from.
+     * @param recoveryKey the recovery key to decrypt the retrieved backup.
+     * @param roomId the id of the room to get backup data from.
+     * @param sessionId the id of the session to restore.
      * @param stepProgressListener the step progress listener
-     * @param callback             Callback. It provides the number of found keys and the number of successfully imported keys.
+     * @param callback Callback. It provides the number of found keys and the number of successfully imported keys.
      */
-    fun restoreKeysWithRecoveryKey(keysVersionResult: KeysVersionResult,
-                                   recoveryKey: String, roomId: String?,
-                                   sessionId: String?,
-                                   stepProgressListener: StepProgressListener?,
-                                   callback: MatrixCallback<ImportRoomKeysResult>)
+    fun restoreKeysWithRecoveryKey(
+            keysVersionResult: KeysVersionResult,
+            recoveryKey: String,
+            roomId: String?,
+            sessionId: String?,
+            stepProgressListener: StepProgressListener?,
+            callback: MatrixCallback<ImportRoomKeysResult>
+    )
 
     /**
      * Restore a backup with a password from a given backup version stored on the homeserver.
@@ -196,18 +215,23 @@ interface KeysBackupService {
      * @param stepProgressListener the step progress listener
      * @param callback Callback. It provides the number of found keys and the number of successfully imported keys.
      */
-    fun restoreKeyBackupWithPassword(keysBackupVersion: KeysVersionResult,
-                                     password: String,
-                                     roomId: String?,
-                                     sessionId: String?,
-                                     stepProgressListener: StepProgressListener?,
-                                     callback: MatrixCallback<ImportRoomKeysResult>)
+    fun restoreKeyBackupWithPassword(
+            keysBackupVersion: KeysVersionResult,
+            password: String,
+            roomId: String?,
+            sessionId: String?,
+            stepProgressListener: StepProgressListener?,
+            callback: MatrixCallback<ImportRoomKeysResult>
+    )
 
     val keysBackupVersion: KeysVersionResult?
+
     val currentBackupVersion: String?
-    val isEnabled: Boolean
-    val isStucked: Boolean
-    val state: KeysBackupState
+        get() = keysBackupVersion?.version
+
+    fun isEnabled(): Boolean
+    fun isStuck(): Boolean
+    fun getState(): KeysBackupState
 
     // For gossiping
     fun saveBackupRecoveryKey(recoveryKey: String?, version: String?)
@@ -215,8 +239,10 @@ interface KeysBackupService {
 
     fun isValidRecoveryKeyForCurrentVersion(recoveryKey: String, callback: MatrixCallback<Boolean>)
 
-    fun computePrivateKey(passphrase: String,
-                          privateKeySalt: String,
-                          privateKeyIterations: Int,
-                          progressListener: ProgressListener): ByteArray
+    fun computePrivateKey(
+            passphrase: String,
+            privateKeySalt: String,
+            privateKeyIterations: Int,
+            progressListener: ProgressListener
+    ): ByteArray
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupState.kt
index a4cc133398203ae4af23b47cc2d8343e4afd09db..a867d573de59cf77bc15bb5872ee87714a984913 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupState.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupState.kt
@@ -51,33 +51,51 @@ package org.matrix.android.sdk.api.session.crypto.keysbackup
  * </pre>
  */
 enum class KeysBackupState {
-    // Need to check the current backup version on the homeserver
+    /**
+     * Need to check the current backup version on the homeserver.
+     */
     Unknown,
 
-    // Checking if backup is enabled on homeserver
+    /**
+     * Checking if backup is enabled on homeserver.
+     */
     CheckingBackUpOnHomeserver,
 
-    // Backup has been stopped because a new backup version has been detected on the homeserver
+    /**
+     * Backup has been stopped because a new backup version has been detected on the homeserver.
+     */
     WrongBackUpVersion,
 
-    // Backup from this device is not enabled
+    /**
+     * Backup from this device is not enabled.
+     */
     Disabled,
 
-    // There is a backup available on the homeserver but it is not trusted.
-    // It is not trusted because the signature is invalid or the device that created it is not verified
-    // Use [KeysBackup.getKeysBackupTrust()] to get trust details.
-    // Consequently, the backup from this device is not enabled.
+    /**
+     * There is a backup available on the homeserver but it is not trusted.
+     * It is not trusted because the signature is invalid or the device that created it is not verified.
+     * Use [KeysBackup.getKeysBackupTrust()] to get trust details.
+     * Consequently, the backup from this device is not enabled.
+     */
     NotTrusted,
 
-    // Backup is being enabled: the backup version is being created on the homeserver
+    /**
+     * Backup is being enabled: the backup version is being created on the homeserver.
+     */
     Enabling,
 
-    // Backup is enabled and ready to send backup to the homeserver
+    /**
+     * Backup is enabled and ready to send backup to the homeserver.
+     */
     ReadyToBackUp,
 
-    // e2e keys are going to be sent to the homeserver
+    /**
+     * e2e keys are going to be sent to the homeserver.
+     */
     WillBackUp,
 
-    // e2e keys are being sent to the homeserver
+    /**
+     * e2e keys are being sent to the homeserver.
+     */
     BackingUp
 }
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 7127c8d3f45063112dbedd822a5e9809b81e45ac..afbf45ac702963c23d8a89dd5cb5ddaa126f9335 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
@@ -40,7 +40,8 @@ sealed class KeysBackupVersionTrustSignature {
             /**
              * Flag to indicate the signature from this device is valid.
              */
-            val valid: Boolean) : KeysBackupVersionTrustSignature()
+            val valid: Boolean
+    ) : KeysBackupVersionTrustSignature()
 
     data class UserSignature(
             val keyId: String?,
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 0c19d275cc375a4f47206fdaf0dc9966ce858d61..4ff196dd07d4d22de995dd66b41586e0bfa9d1a0 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
@@ -48,8 +48,7 @@ data class IncomingRoomKeyRequest(
         /**
          * Factory.
          *
-         * @param event the event
-         * @param currentTimeMillis the current time in milliseconds
+         * @param trail the AuditTrail data
          */
         fun fromEvent(trail: AuditTrail): IncomingRoomKeyRequest? {
             return trail
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 744fe74d0da947bf5b0b2d141cf340f4a8b6e6e9..736ae6b318d0919c05207034da1605f2bdf0222d 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
@@ -46,8 +46,8 @@ class MXUsersDevicesMap<E> {
     /**
      * Provides the object for a device id and a user Id.
      *
+     * @param userId the user id
      * @param deviceId the device id
-     * @param userId   the object id
      * @return the object
      */
     fun getObject(userId: String?, deviceId: String?): E? {
@@ -59,9 +59,9 @@ class MXUsersDevicesMap<E> {
     /**
      * Set an object for a dedicated user Id and device Id.
      *
-     * @param userId   the user Id
+     * @param userId the user Id
      * @param deviceId the device id
-     * @param o        the object to set
+     * @param o the object to set
      */
     fun setObject(userId: String?, deviceId: String?, o: E?) {
         if (null != o && userId?.isNotBlank() == true && deviceId?.isNotBlank() == true) {
@@ -73,8 +73,8 @@ class MXUsersDevicesMap<E> {
     /**
      * Defines the objects map for a user Id.
      *
+     * @param userId the user id
      * @param objectsPerDevices the objects maps
-     * @param userId            the user id
      */
     fun setObjects(userId: String?, objectsPerDevices: Map<String, E>?) {
         if (!userId.isNullOrBlank()) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomEncryptionTrustLevel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomEncryptionTrustLevel.kt
index 68c7496d58d65aa7d1a5a759b50b3fd9b114f368..78724819a3f298bc78bc421fa869263ea884d78e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomEncryptionTrustLevel.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomEncryptionTrustLevel.kt
@@ -20,15 +20,23 @@ package org.matrix.android.sdk.api.session.crypto.model
  * RoomEncryptionTrustLevel represents the trust level in an encrypted room.
  */
 enum class RoomEncryptionTrustLevel {
-    // No one in the room has been verified -> Black shield
+    /**
+     * No one in the room has been verified -> Black shield.
+     */
     Default,
 
-    // There are one or more device un-verified -> the app should display a red shield
+    /**
+     * There are one or more device un-verified -> the app should display a red shield.
+     */
     Warning,
 
-    // All devices in the room are verified -> the app should display a green shield
+    /**
+     * All devices in the room are verified -> the app should display a green shield.
+     */
     Trusted,
 
-    // e2e is active but with an unsupported algorithm
+    /**
+     * e2e is active but with an unsupported algorithm.
+     */
     E2EWithUnsupportedAlgorithm
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/CancelCode.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/CancelCode.kt
index 5a025f37e151459b3750c3a9ee96a2cb25ba26fb..e4716d7794ba7753e89781cd1c8d469f7bac4b17 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/CancelCode.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/CancelCode.kt
@@ -28,7 +28,8 @@ enum class CancelCode(val value: String, val humanReadable: String) {
     MismatchedKeys("m.key_mismatch", "Key mismatch"),
     UserError("m.user_error", "User error"),
     MismatchedUser("m.user_mismatch", "User mismatch"),
-    QrCodeInvalid("m.qr_code.invalid", "Invalid QR code")
+    QrCodeInvalid("m.qr_code.invalid", "Invalid QR code"),
+    AcceptedByAnotherDevice("m.accepted", "Verification request accepted by another device")
 }
 
 fun safeValueOf(code: String?): CancelCode {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/EmojiRepresentation.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/EmojiRepresentation.kt
index 2c1bf9ff4df3fd1167c9d6ba95e236645a8d8c79..5402471e466d3ccea3f3e802641f525c696e9632 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/EmojiRepresentation.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/EmojiRepresentation.kt
@@ -19,7 +19,8 @@ package org.matrix.android.sdk.api.session.crypto.verification
 import androidx.annotation.DrawableRes
 import androidx.annotation.StringRes
 
-data class EmojiRepresentation(val emoji: String,
-                               @StringRes val nameResId: Int,
-                               @DrawableRes val drawableRes: Int? = null
+data class EmojiRepresentation(
+        val emoji: String,
+        @StringRes val nameResId: Int,
+        @DrawableRes val drawableRes: Int? = null
 )
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 f2de2c4b47ed2fedd920021d9dcd21e5d9a6a9ee..0ab47a2ecdedadd137d7578d8b2f7e0c2f8b06bb 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
@@ -20,12 +20,18 @@ package org.matrix.android.sdk.api.session.crypto.verification
  * Verification methods.
  */
 enum class VerificationMethod {
-    // Use it when your application supports the SAS verification method
+    /**
+     * Use it when your application supports the SAS verification method.
+     */
     SAS,
 
-    // Use it if your application is able to display QR codes
+    /**
+     * Use it if your application is able to display QR codes.
+     */
     QR_CODE_SHOW,
 
-    // Use it if your application is able to scan QR codes
+    /**
+     * Use it if your application is able to scan QR codes.
+     */
     QR_CODE_SCAN
 }
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 321ec7309403b5a961b96a7f26ae85e214b32fb2..ee93f149927bbfeccce33e2b3da083ced6e56439 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
@@ -46,54 +46,68 @@ interface VerificationService {
 
     fun getExistingVerificationRequestInRoom(roomId: String, tid: String?): PendingVerificationRequest?
 
-    fun beginKeyVerification(method: VerificationMethod,
-                             otherUserId: String,
-                             otherDeviceId: String,
-                             transactionId: String?): String?
+    fun beginKeyVerification(
+            method: VerificationMethod,
+            otherUserId: String,
+            otherDeviceId: String,
+            transactionId: String?
+    ): String?
 
     /**
      * Request key verification with another user via room events (instead of the to-device API).
      */
-    fun requestKeyVerificationInDMs(methods: List<VerificationMethod>,
-                                    otherUserId: String,
-                                    roomId: String,
-                                    localId: String? = LocalEcho.createLocalEchoId()): PendingVerificationRequest
+    fun requestKeyVerificationInDMs(
+            methods: List<VerificationMethod>,
+            otherUserId: String,
+            roomId: String,
+            localId: String? = LocalEcho.createLocalEchoId()
+    ): PendingVerificationRequest
 
     fun cancelVerificationRequest(request: PendingVerificationRequest)
 
     /**
      * Request a key verification from another user using toDevice events.
      */
-    fun requestKeyVerification(methods: List<VerificationMethod>,
-                               otherUserId: String,
-                               otherDevices: List<String>?): PendingVerificationRequest
-
-    fun declineVerificationRequestInDMs(otherUserId: String,
-                                        transactionId: String,
-                                        roomId: String)
+    fun requestKeyVerification(
+            methods: List<VerificationMethod>,
+            otherUserId: String,
+            otherDevices: List<String>?
+    ): PendingVerificationRequest
+
+    fun declineVerificationRequestInDMs(
+            otherUserId: String,
+            transactionId: String,
+            roomId: String
+    )
 
     // Only SAS method is supported for the moment
     // TODO Parameter otherDeviceId should be removed in this case
-    fun beginKeyVerificationInDMs(method: VerificationMethod,
-                                  transactionId: String,
-                                  roomId: String,
-                                  otherUserId: String,
-                                  otherDeviceId: String): String
+    fun beginKeyVerificationInDMs(
+            method: VerificationMethod,
+            transactionId: String,
+            roomId: String,
+            otherUserId: String,
+            otherDeviceId: String
+    ): String
 
     /**
      * Returns false if the request is unknown.
      */
-    fun readyPendingVerificationInDMs(methods: List<VerificationMethod>,
-                                      otherUserId: String,
-                                      roomId: String,
-                                      transactionId: String): Boolean
+    fun readyPendingVerificationInDMs(
+            methods: List<VerificationMethod>,
+            otherUserId: String,
+            roomId: String,
+            transactionId: String
+    ): Boolean
 
     /**
      * Returns false if the request is unknown.
      */
-    fun readyPendingVerification(methods: List<VerificationMethod>,
-                                 otherUserId: String,
-                                 transactionId: String): Boolean
+    fun readyPendingVerification(
+            methods: List<VerificationMethod>,
+            otherUserId: String,
+            transactionId: String
+    ): Boolean
 
     interface Listener {
         /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTxState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTxState.kt
index 39de2cc7120d1177f429ec2035e776785128cbb3..30e4c6693753f00eb840227218bc126604c67664 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTxState.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTxState.kt
@@ -17,10 +17,14 @@
 package org.matrix.android.sdk.api.session.crypto.verification
 
 sealed class VerificationTxState {
-    // Uninitialized state
+    /**
+     * Uninitialized state.
+     */
     object None : VerificationTxState()
 
-    // Specific for SAS
+    /**
+     * Specific for SAS.
+     */
     abstract class VerificationSasTxState : VerificationTxState()
 
     object SendingStart : VerificationSasTxState()
@@ -38,18 +42,26 @@ sealed class VerificationTxState {
     object MacSent : VerificationSasTxState()
     object Verifying : VerificationSasTxState()
 
-    // Specific for QR code
+    /**
+     * Specific for QR code.
+     */
     abstract class VerificationQrTxState : VerificationTxState()
 
-    // Will be used to ask the user if the other user has correctly scanned
+    /**
+     * Will be used to ask the user if the other user has correctly scanned.
+     */
     object QrScannedByOther : VerificationQrTxState()
     object WaitingOtherReciprocateConfirm : VerificationQrTxState()
 
-    // Terminal states
+    /**
+     * Terminal states.
+     */
     abstract class TerminalTxState : VerificationTxState()
 
     object Verified : TerminalTxState()
 
-    // Cancelled by me or by other
+    /**
+     * Cancelled by me or by other.
+     */
     data class Cancelled(val cancelCode: CancelCode, val byMe: Boolean) : TerminalTxState()
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/EventService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/EventService.kt
index 297f277497f13e48f59392b00a08c55eaaab9b98..7f275bf95291e8c968619b9b820a864859e49080 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/EventService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/EventService.kt
@@ -24,6 +24,8 @@ interface EventService {
      * Ask the homeserver for an event content. The SDK will try to decrypt it if it is possible
      * The result will not be stored into cache
      */
-    suspend fun getEvent(roomId: String,
-                         eventId: String): Event
+    suspend fun getEvent(
+            roomId: String,
+            eventId: String
+    ): Event
 }
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 16bdbd3432bd5bfb1d67a999af754803ff361c0a..7f9ab4c6dd61faa8434ee462819570167dde7e09 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
@@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
 import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
 import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
+import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageContent
 import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
@@ -211,13 +212,13 @@ data class Event(
 
         return when {
             isReplyRenderedInThread() || isQuote() -> ContentUtils.extractUsefulTextFromReply(text)
-            isFileMessage()                        -> "sent a file."
-            isAudioMessage()                       -> "sent an audio file."
-            isImageMessage()                       -> "sent an image."
-            isVideoMessage()                       -> "sent a video."
-            isSticker()                            -> "sent a sticker"
-            isPoll()                               -> getPollQuestion() ?: "created a poll."
-            else                                   -> text
+            isFileMessage() -> "sent a file."
+            isAudioMessage() -> "sent an audio file."
+            isImageMessage() -> "sent an image."
+            isVideoMessage() -> "sent a video."
+            isSticker() -> "sent a sticker"
+            isPoll() -> getPollQuestion() ?: "created a poll."
+            else -> text
         }
     }
 
@@ -317,35 +318,35 @@ fun Event.isTextMessage(): Boolean {
         MessageType.MSGTYPE_TEXT,
         MessageType.MSGTYPE_EMOTE,
         MessageType.MSGTYPE_NOTICE -> true
-        else                       -> false
+        else -> false
     }
 }
 
 fun Event.isImageMessage(): Boolean {
     return when (getMsgType()) {
         MessageType.MSGTYPE_IMAGE -> true
-        else                      -> false
+        else -> false
     }
 }
 
 fun Event.isVideoMessage(): Boolean {
     return when (getMsgType()) {
         MessageType.MSGTYPE_VIDEO -> true
-        else                      -> false
+        else -> false
     }
 }
 
 fun Event.isAudioMessage(): Boolean {
     return when (getMsgType()) {
         MessageType.MSGTYPE_AUDIO -> true
-        else                      -> false
+        else -> false
     }
 }
 
 fun Event.isFileMessage(): Boolean {
     return when (getMsgType()) {
         MessageType.MSGTYPE_FILE -> true
-        else                     -> false
+        else -> false
     }
 }
 
@@ -355,14 +356,14 @@ fun Event.isAttachmentMessage(): Boolean {
         MessageType.MSGTYPE_AUDIO,
         MessageType.MSGTYPE_VIDEO,
         MessageType.MSGTYPE_FILE -> true
-        else                     -> false
+        else -> false
     }
 }
 
 fun Event.isLocationMessage(): Boolean {
     return when (getMsgType()) {
         MessageType.MSGTYPE_LOCATION -> true
-        else                         -> false
+        else -> false
     }
 }
 
@@ -375,11 +376,11 @@ fun Event.getRelationContent(): RelationDefaultContent? {
         content.toModel<EncryptedEventContent>()?.relatesTo
     } else {
         content.toModel<MessageContent>()?.relatesTo ?: run {
-            // Special case to handle stickers, while there is only a local msgtype for stickers
-            if (getClearType() == EventType.STICKER) {
-                getClearContent().toModel<MessageStickerContent>()?.relatesTo
-            } else {
-                null
+            // Special cases when there is only a local msgtype for some event types
+            when (getClearType()) {
+                EventType.STICKER -> getClearContent().toModel<MessageStickerContent>()?.relatesTo
+                in EventType.BEACON_LOCATION_DATA -> getClearContent().toModel<MessageBeaconLocationDataContent>()?.relatesTo
+                else -> null
             }
         }
     }
@@ -426,3 +427,6 @@ fun Event.getPollContent(): MessagePollContent? {
 
 fun Event.supportsNotification() =
         this.getClearType() in EventType.MESSAGE + EventType.POLL_START + EventType.STATE_ROOM_BEACON_INFO
+
+fun Event.isContentReportable() =
+        this.getClearType() in EventType.MESSAGE + EventType.STATE_ROOM_BEACON_INFO
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 d58c3614a70af1f0ef522243c0595dcacc1b79d6..fb8b65c4f279c265e25d8627ef7619d00e473265 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
@@ -98,12 +98,12 @@ enum class WithHeldCode(val value: String) {
     companion object {
         fun fromCode(code: String?): WithHeldCode? {
             return when (code) {
-                BLACKLISTED.value  -> BLACKLISTED
-                UNVERIFIED.value   -> UNVERIFIED
+                BLACKLISTED.value -> BLACKLISTED
+                UNVERIFIED.value -> UNVERIFIED
                 UNAUTHORISED.value -> UNAUTHORISED
-                UNAVAILABLE.value  -> UNAVAILABLE
-                NO_OLM.value       -> NO_OLM
-                else               -> null
+                UNAVAILABLE.value -> UNAVAILABLE
+                NO_OLM.value -> NO_OLM
+                else -> null
             }
         }
     }
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 84a99908268ecccf607f51473b7e9cb90ddea35b..ca6c889cb84506f5e0fe9b147437d6918e90ad63 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
@@ -33,7 +33,7 @@ interface FileService {
         /**
          * The original file is in cache, but the decrypted files can be deleted for security reason.
          * To decrypt the file again, call [downloadFile], the encrypted file will not be downloaded again
-         * @param decryptedFileInCache true if the decrypted file is available. Always true for clear files.
+         * @property decryptedFileInCache true if the decrypted file is available. Always true for clear files.
          */
         data class InCache(val decryptedFileInCache: Boolean) : FileState()
         object Downloading : FileState()
@@ -44,10 +44,12 @@ interface FileService {
      * Download a file if necessary and ensure that if the file is encrypted, the file is decrypted.
      * Result will be a decrypted file, stored in the cache folder. url parameter will be used to create unique filename to avoid name collision.
      */
-    suspend fun downloadFile(fileName: String,
-                             mimeType: String?,
-                             url: String?,
-                             elementToDecrypt: ElementToDecrypt?): File
+    suspend fun downloadFile(
+            fileName: String,
+            mimeType: String?,
+            url: String?,
+            elementToDecrypt: ElementToDecrypt?
+    ): File
 
     suspend fun downloadFile(messageContent: MessageWithAttachmentContent): File =
             downloadFile(
@@ -57,10 +59,11 @@ interface FileService {
                     elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt()
             )
 
-    fun isFileInCache(mxcUrl: String?,
-                      fileName: String,
-                      mimeType: String?,
-                      elementToDecrypt: ElementToDecrypt?
+    fun isFileInCache(
+            mxcUrl: String?,
+            fileName: String,
+            mimeType: String?,
+            elementToDecrypt: ElementToDecrypt?
     ): Boolean
 
     fun isFileInCache(messageContent: MessageWithAttachmentContent) =
@@ -75,10 +78,12 @@ interface FileService {
      * Use this URI and pass it to intent using flag Intent.FLAG_GRANT_READ_URI_PERMISSION
      * (if not other app won't be able to access it).
      */
-    fun getTemporarySharableURI(mxcUrl: String?,
-                                fileName: String,
-                                mimeType: String?,
-                                elementToDecrypt: ElementToDecrypt?): Uri?
+    fun getTemporarySharableURI(
+            mxcUrl: String?,
+            fileName: String,
+            mimeType: String?,
+            elementToDecrypt: ElementToDecrypt?
+    ): Uri?
 
     fun getTemporarySharableURI(messageContent: MessageWithAttachmentContent): Uri? =
             getTemporarySharableURI(
@@ -92,10 +97,12 @@ interface FileService {
      * Get information on the given file.
      * Mimetype should be the same one as passed to downloadFile (limitation for now)
      */
-    fun fileState(mxcUrl: String?,
-                  fileName: String,
-                  mimeType: String?,
-                  elementToDecrypt: ElementToDecrypt?): FileState
+    fun fileState(
+            mxcUrl: String?,
+            fileName: String,
+            mimeType: String?,
+            elementToDecrypt: ElementToDecrypt?
+    ): FileState
 
     fun fileState(messageContent: MessageWithAttachmentContent): FileState =
             fileState(
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 5b06fdacae2c938fa9126c3a398ac94d488d309e..c78fb9cf7928c372435b2930d6d0b8f3f9be3eda 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
@@ -81,13 +81,13 @@ data class HomeServerCapabilities(
         val versionCap = roomVersions.supportedVersion.firstOrNull { it.version == preferred }
 
         return when {
-            versionCap == null                            -> {
+            versionCap == null -> {
                 RoomCapabilitySupport.UNKNOWN
             }
             versionCap.status == RoomVersionStatus.STABLE -> {
                 RoomCapabilitySupport.SUPPORTED
             }
-            else                                          -> {
+            else -> {
                 RoomCapabilitySupport.SUPPORTED_UNSTABLE
             }
         }
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 c03b42e6c894037487126dc7e7b133be156ace9b..2fb35d38e32a6b44155495961016d02069091f4d 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
@@ -74,6 +74,7 @@ interface IdentityService {
     /**
      * 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 threePid the three pid
      * @param code the code sent to the user
      */
     suspend fun submitValidationToken(threePid: ThreePid, code: String)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt
index 42d777849b80c8eb64728ce4b7182fe4dfbf7028..6bcf576824e57d896bff863be83dd64bf43a0a9c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt
@@ -27,7 +27,7 @@ sealed class ThreePid(open val value: String) {
 
 internal fun ThreePid.toMedium(): String {
     return when (this) {
-        is ThreePid.Email  -> ThirdPartyIdentifier.MEDIUM_EMAIL
+        is ThreePid.Email -> ThirdPartyIdentifier.MEDIUM_EMAIL
         is ThreePid.Msisdn -> ThirdPartyIdentifier.MEDIUM_MSISDN
     }
 }
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
deleted file mode 100644
index 7006e117512bf4405c7f17e52f2334f2c52f57a3..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/SyncStatusService.kt
+++ /dev/null
@@ -1,50 +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.initsync
-
-import androidx.lifecycle.LiveData
-
-interface SyncStatusService {
-
-    fun getSyncStatusLive(): LiveData<Status>
-
-    sealed class Status {
-        /**
-         * For initial sync.
-         */
-        abstract class InitialSyncStatus : Status()
-
-        object Idle : InitialSyncStatus()
-        data class InitialSyncProgressing(
-                val initSyncStep: InitSyncStep,
-                val percentProgress: Int = 0
-        ) : InitialSyncStatus()
-
-        /**
-         * For incremental sync.
-         */
-        abstract class IncrementalSyncStatus : Status()
-
-        object IncrementalSyncIdle : IncrementalSyncStatus()
-        data class IncrementalSyncParsing(
-                val rooms: Int,
-                val toDevice: Int
-        ) : IncrementalSyncStatus()
-
-        object IncrementalSyncError : IncrementalSyncStatus()
-        object IncrementalSyncDone : IncrementalSyncStatus()
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/integrationmanager/IntegrationManagerService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/integrationmanager/IntegrationManagerService.kt
index 60af93888e65063f3ce1cf03f4bdb4164459d52a..5b15a0cb1368f5b7eff1643d81c089f1e7ab1e38 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/integrationmanager/IntegrationManagerService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/integrationmanager/IntegrationManagerService.kt
@@ -99,6 +99,7 @@ interface IntegrationManagerService {
      * Offers to allow or disallow a native widget domain.
      * @param widgetType the widget type to check for
      * @param domain the domain to check for
+     * @param allowed true or false
      */
     suspend fun setNativeWidgetDomainAllowed(widgetType: String, domain: String, allowed: Boolean)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixLinkify.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixLinkify.kt
index c5d919407aecbf50ea6a03239c0a07266a520c7d..c428e40203000b4a998bc909bf3f63cc6d6a2fe7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixLinkify.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixLinkify.kt
@@ -29,6 +29,7 @@ object MatrixLinkify {
      * Find the matrix spans i.e matrix id , user id ... to display them as URL.
      *
      * @param spannable the text in which the matrix items has to be clickable.
+     * @param callback listener to be notified when the span is clicked
      */
     @Suppress("UNUSED_PARAMETER")
     fun addLinks(spannable: Spannable, callback: MatrixPermalinkSpan.Callback?): Boolean {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixPermalinkSpan.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixPermalinkSpan.kt
index 2f8f5f99a53e7cbb5792485b04c9946d27372893..9c71c081beda14ba4a5037f8c7bb0895e04bc11d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixPermalinkSpan.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixPermalinkSpan.kt
@@ -22,11 +22,13 @@ import org.matrix.android.sdk.api.session.permalinks.MatrixPermalinkSpan.Callbac
 
 /**
  * This MatrixPermalinkSpan is a clickable span which use a [Callback] to communicate back.
- * @param url the permalink url tied to the span
- * @param callback the callback to use.
+ * @property url the permalink url tied to the span
+ * @property callback the callback to use.
  */
-class MatrixPermalinkSpan(private val url: String,
-                          private val callback: Callback? = null) : ClickableSpan() {
+class MatrixPermalinkSpan(
+        private val url: String,
+        private val callback: Callback? = null
+) : ClickableSpan() {
 
     interface Callback {
         fun onUrlClicked(url: String)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixToConverter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixToConverter.kt
index a904e89681a554a44a62921860f2f2f8fb962a1d..c418b59df41bc04c8143ef4d6037c52b44b7353d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixToConverter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixToConverter.kt
@@ -38,12 +38,12 @@ object MatrixToConverter {
             // URL is already a matrix.to
             uriString.startsWith(PermalinkService.MATRIX_TO_URL_BASE) -> uri
             // Web or client url
-            SUPPORTED_PATHS.any { it in uriString }                   -> {
+            SUPPORTED_PATHS.any { it in uriString } -> {
                 val path = SUPPORTED_PATHS.first { it in uriString }
                 Uri.parse(PermalinkService.MATRIX_TO_URL_BASE + uriString.substringAfter(path))
             }
             // URL is not supported
-            else                                                      -> null
+            else -> null
         }
     }
 
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 9d078dc4b243e1f9ff0b5407a22c6f29364e8198..0168b7ac3ab6e9679916da9ecf416a0fdf5205f4 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
@@ -67,10 +67,10 @@ object PermalinkParser {
         val identifier = params.getOrNull(0)
         val extraParameter = params.getOrNull(1)
         return when {
-            identifier.isNullOrEmpty()             -> PermalinkData.FallbackLink(uri)
-            MatrixPatterns.isUserId(identifier)    -> PermalinkData.UserLink(userId = identifier)
-            MatrixPatterns.isGroupId(identifier)   -> PermalinkData.GroupLink(groupId = identifier)
-            MatrixPatterns.isRoomId(identifier)    -> {
+            identifier.isNullOrEmpty() -> PermalinkData.FallbackLink(uri)
+            MatrixPatterns.isUserId(identifier) -> PermalinkData.UserLink(userId = identifier)
+            MatrixPatterns.isGroupId(identifier) -> PermalinkData.GroupLink(groupId = identifier)
+            MatrixPatterns.isRoomId(identifier) -> {
                 handleRoomIdCase(fragment, identifier, matrixToUri, extraParameter, viaQueryParameters)
             }
             MatrixPatterns.isRoomAlias(identifier) -> {
@@ -81,7 +81,7 @@ object PermalinkParser {
                         viaParameters = viaQueryParameters
                 )
             }
-            else                                   -> PermalinkData.FallbackLink(uri)
+            else -> PermalinkData.FallbackLink(uri)
         }
     }
 
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 b49b80df099c87206773cf54898bc717f97b7c98..1788bf7bd2466d3ac7a53bca0d16e319c783bec9 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
@@ -60,6 +60,7 @@ interface PermalinkService {
      * Creates a permalink for a roomId, including the via parameters.
      *
      * @param roomId the room id
+     * @param viaServers the via parameter
      * @param forceMatrixTo whether we should force using matrix.to base URL
      *
      * @return the permalink, or null in case of error
@@ -70,7 +71,7 @@ interface PermalinkService {
      * Creates a permalink for an event. If you have an event you can use [createPermalink]
      * Ex: "https://matrix.to/#/!nbzmcXAqpxBXjAdgoX:matrix.org/$1531497316352799BevdV:matrix.org?via=matrix.org"
      *
-     * @param roomId  the id of the room
+     * @param roomId the id of the room
      * @param eventId the id of the event
      * @param forceMatrixTo whether we should force using matrix.to base URL
      *
@@ -90,7 +91,7 @@ interface PermalinkService {
      * Creates a HTML or Markdown mention span template. Can be used to replace a mention with a permalink to mentioned user.
      * Ex: "<a href=\"https://matrix.to/#/%1\$s\">%2\$s</a>" or "[%2\$s](https://matrix.to/#/%1\$s)"
      *
-     * @param type: type of template to create
+     * @param type type of template to create
      * @param forceMatrixTo whether we should force using matrix.to base URL
      *
      * @return the created template
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 095f2ef7c2c9058f463c4b361a73eb05e76fb9fa..4c00c764593c5c1f93fe46583d013e2b083ab62e 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
@@ -107,8 +107,10 @@ interface ProfileService {
     /**
      * Finalize adding a 3Pids. Call this method once the user has validated that he owns the ThreePid.
      */
-    suspend fun finalizeAddingThreePid(threePid: ThreePid,
-                                       userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor)
+    suspend fun finalizeAddingThreePid(
+            threePid: ThreePid,
+            userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor
+    )
 
     /**
      * Cancel adding a threepid. It will remove locally stored data about this ThreePid.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/HttpPusher.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/HttpPusher.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1ae23e2b7015c7dd58163ab0dad7a67fc489df37
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/HttpPusher.kt
@@ -0,0 +1,73 @@
+/*
+ * 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.pushers
+
+data class HttpPusher(
+        /**
+         * This is a unique identifier for this pusher. The value you should use for
+         * this is the routing or destination address information for the notification,
+         * for example, the APNS token for APNS or the Registration ID for GCM. If your
+         * notification client has no such concept, use any unique identifier. Max length, 512 chars.
+         */
+        val pushkey: String,
+
+        /**
+         * The application id
+         * This is a reverse-DNS style identifier for the application. It is recommended
+         * that this end with the platform, such that different platform versions get
+         * different app identifiers. Max length, 64 chars.
+         */
+        val appId: String,
+
+        /**
+         * This string determines which set of device specific rules this pusher executes.
+         */
+        val profileTag: String,
+
+        /**
+         * The preferred language for receiving notifications (e.g. "en" or "en-US").
+         */
+        val lang: String,
+
+        /**
+         * A human readable string that will allow the user to identify what application owns this pusher.
+         */
+        val appDisplayName: String,
+
+        /**
+         * A human readable string that will allow the user to identify what device owns this pusher.
+         */
+        val deviceDisplayName: String,
+
+        /**
+         * The URL to use to send notifications to. MUST be an HTTPS URL with a path of /_matrix/push/v1/notify.
+         */
+        val url: String,
+
+        /**
+         * If true, the homeserver should add another pusher with the given pushkey and App ID in addition
+         * to any others with different user IDs. Otherwise, the homeserver must remove any other pushers
+         * with the same App ID and pushkey for different users.
+         */
+        val append: Boolean,
+
+        /**
+         * true to limit the push content to only id and not message content
+         * Ref: https://matrix.org/docs/spec/push_gateway/r0.1.1#homeserver-behaviour
+         */
+        val withEventIdOnly: Boolean
+)
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 5f9857eb2fbb60a19848ead18578bb8ae454675f..d7958ea3cdd0f6e44c1ab00577687fb3efa836ed 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
@@ -47,23 +47,25 @@ interface PushersService {
      * Add a new Email pusher.
      * Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-pushers-set
      *
-     * @param email             The email address to send notifications to.
-     * @param lang              The preferred language for receiving notifications (e.g. "en" or "en-US").
-     * @param emailBranding     The branding placeholder to include in the email communications.
-     * @param appDisplayName    A human readable string that will allow the user to identify what application owns this pusher.
+     * @param email The email address to send notifications to.
+     * @param lang The preferred language for receiving notifications (e.g. "en" or "en-US").
+     * @param emailBranding The branding placeholder to include in the email communications.
+     * @param appDisplayName A human readable string that will allow the user to identify what application owns this pusher.
      * @param deviceDisplayName A human readable string that will allow the user to identify what device owns this pusher.
-     * @param append            If true, the homeserver should add another pusher with the given pushkey and App ID in addition
+     * @param append If true, the homeserver should add another pusher with the given pushkey and App ID in addition
      *                          to any others with different user IDs. Otherwise, the homeserver must remove any other pushers
      *                          with the same App ID and pushkey for different users. Typically We always want to append for
      *                          email pushers since we don't want to stop other accounts notifying to the same email address.
      * @throws [InvalidParameterException] if a parameter is not correct
      */
-    suspend fun addEmailPusher(email: String,
-                               lang: String,
-                               emailBranding: String,
-                               appDisplayName: String,
-                               deviceDisplayName: String,
-                               append: Boolean = true)
+    suspend fun addEmailPusher(
+            email: String,
+            lang: String,
+            emailBranding: String,
+            appDisplayName: String,
+            deviceDisplayName: String,
+            append: Boolean = true
+    )
 
     /**
      * Directly ask the push gateway to send a push to this device.
@@ -75,10 +77,12 @@ interface PushersService {
      * @param pushkey the FCM token
      * @param eventId the eventId which will be sent in the Push message. Use a fake eventId.
      */
-    suspend fun testPush(url: String,
-                         appId: String,
-                         pushkey: String,
-                         eventId: String)
+    suspend fun testPush(
+            url: String,
+            appId: String,
+            pushkey: String,
+            eventId: String
+    )
 
     /**
      * Remove a registered pusher.
@@ -107,61 +111,4 @@ interface PushersService {
      * Get the current pushers.
      */
     fun getPushers(): List<Pusher>
-
-    data class HttpPusher(
-
-            /**
-             * This is a unique identifier for this pusher. The value you should use for
-             * this is the routing or destination address information for the notification,
-             * for example, the APNS token for APNS or the Registration ID for GCM. If your
-             * notification client has no such concept, use any unique identifier. Max length, 512 chars.
-             */
-            val pushkey: String,
-
-            /**
-             * The application id
-             * This is a reverse-DNS style identifier for the application. It is recommended
-             * that this end with the platform, such that different platform versions get
-             * different app identifiers. Max length, 64 chars.
-             */
-            val appId: String,
-
-            /**
-             * This string determines which set of device specific rules this pusher executes.
-             */
-            val profileTag: String,
-
-            /**
-             * The preferred language for receiving notifications (e.g. "en" or "en-US").
-             */
-            val lang: String,
-
-            /**
-             * A human readable string that will allow the user to identify what application owns this pusher.
-             */
-            val appDisplayName: String,
-
-            /**
-             * A human readable string that will allow the user to identify what device owns this pusher.
-             */
-            val deviceDisplayName: String,
-
-            /**
-             * The URL to use to send notifications to. MUST be an HTTPS URL with a path of /_matrix/push/v1/notify.
-             */
-            val url: String,
-
-            /**
-             * If true, the homeserver should add another pusher with the given pushkey and App ID in addition
-             * to any others with different user IDs. Otherwise, the homeserver must remove any other pushers
-             * with the same App ID and pushkey for different users.
-             */
-            val append: Boolean,
-
-            /**
-             * true to limit the push content to only id and not message content
-             * Ref: https://matrix.org/docs/spec/push_gateway/r0.1.1#homeserver-behaviour
-             */
-            val withEventIdOnly: Boolean
-    )
 }
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 2b2930c1ba01022e4352c076647a3563ef1d532e..6122aae972e8a7b4bc88daaed1909f65077b79ed 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
@@ -71,15 +71,15 @@ sealed class Action {
 fun List<Action>.toJson(): List<Any> {
     return map { action ->
         when (action) {
-            is Action.Notify      -> Action.ACTION_NOTIFY
+            is Action.Notify -> Action.ACTION_NOTIFY
             is Action.DoNotNotify -> Action.ACTION_DONT_NOTIFY
-            is Action.Sound       -> {
+            is Action.Sound -> {
                 mapOf(
                         Action.ACTION_OBJECT_SET_TWEAK_KEY to Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND,
                         Action.ACTION_OBJECT_VALUE_KEY to action.sound
                 )
             }
-            is Action.Highlight   -> {
+            is Action.Highlight -> {
                 mapOf(
                         Action.ACTION_OBJECT_SET_TWEAK_KEY to Action.ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT,
                         Action.ACTION_OBJECT_VALUE_KEY to action.highlight
@@ -94,11 +94,11 @@ fun PushRule.getActions(): List<Action> {
 
     actions.forEach { actionStrOrObj ->
         when (actionStrOrObj) {
-            Action.ACTION_NOTIFY      -> Action.Notify
+            Action.ACTION_NOTIFY -> Action.Notify
             Action.ACTION_DONT_NOTIFY -> Action.DoNotNotify
-            is Map<*, *>              -> {
+            is Map<*, *> -> {
                 when (actionStrOrObj[Action.ACTION_OBJECT_SET_TWEAK_KEY]) {
-                    Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND     -> {
+                    Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> {
                         (actionStrOrObj[Action.ACTION_OBJECT_VALUE_KEY] as? String)?.let { stringValue ->
                             Action.Sound(stringValue)
                         }
@@ -112,13 +112,13 @@ fun PushRule.getActions(): List<Action> {
                         // When the value is not there, default is true, says the spec
                                 ?: Action.Highlight(true)
                     }
-                    else                                           -> {
+                    else -> {
                         Timber.w("Unsupported set_tweak value ${actionStrOrObj[Action.ACTION_OBJECT_SET_TWEAK_KEY]}")
                         null
                     }
                 }
             }
-            else                      -> {
+            else -> {
                 Timber.w("Unsupported action type $actionStrOrObj")
                 null
             }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ConditionResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ConditionResolver.kt
index f8a930f987d1cd51ba5716f9ca5746e6ce159a63..d64ee5f77763477f70c47161741e567b2593b44e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ConditionResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ConditionResolver.kt
@@ -22,15 +22,23 @@ import org.matrix.android.sdk.api.session.events.model.Event
  * This class as all required context needed to evaluate rules
  */
 interface ConditionResolver {
-    fun resolveEventMatchCondition(event: Event,
-                                   condition: EventMatchCondition): Boolean
+    fun resolveEventMatchCondition(
+            event: Event,
+            condition: EventMatchCondition
+    ): Boolean
 
-    fun resolveRoomMemberCountCondition(event: Event,
-                                        condition: RoomMemberCountCondition): Boolean
+    fun resolveRoomMemberCountCondition(
+            event: Event,
+            condition: RoomMemberCountCondition
+    ): Boolean
 
-    fun resolveSenderNotificationPermissionCondition(event: Event,
-                                                     condition: SenderNotificationPermissionCondition): Boolean
+    fun resolveSenderNotificationPermissionCondition(
+            event: Event,
+            condition: SenderNotificationPermissionCondition
+    ): Boolean
 
-    fun resolveContainsDisplayNameCondition(event: Event,
-                                            condition: ContainsDisplayNameCondition): Boolean
+    fun resolveContainsDisplayNameCondition(
+            event: Event,
+            condition: ContainsDisplayNameCondition
+    ): Boolean
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt
index 69dd14ddc2c2468e6ea05150cf89c4dcf6a9a353..0bf14345b93c1b8b232ebd2222774ff62aaaa81e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt
@@ -39,7 +39,7 @@ class ContainsDisplayNameCondition : Condition {
             // EventType.ENCRYPTED -> {
             //     event.root.getClearContent()?.toModel<MessageContent>()
             // }
-            else              -> null
+            else -> null
         } ?: return false
 
         return message.body.caseInsensitiveFind(displayName)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt
index 463f3c2a73d0b4870b8a2e2ae718bcffe5ead215..bba6fe602694411fea2c6ebe252300232d60ae7c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt
@@ -27,11 +27,11 @@ enum class Kind(val value: String) {
 
         fun fromString(value: String): Kind {
             return when (value) {
-                "event_match"                    -> EventMatch
-                "contains_display_name"          -> ContainsDisplayName
-                "room_member_count"              -> RoomMemberCount
+                "event_match" -> EventMatch
+                "contains_display_name" -> ContainsDisplayName
+                "room_member_count" -> RoomMemberCount
                 "sender_notification_permission" -> SenderNotificationPermission
-                else                             -> Unrecognised
+                else -> Unrecognised
             }
         }
     }
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 bc4860be1153d3aebb783d9d66b2c6aa1650643f..8f9c25fd30909fecaa4037772d886760b8b4d75e 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
@@ -34,10 +34,11 @@ interface PushRuleService {
 
     /**
      * Enables/Disables a push rule and updates the actions if necessary.
+     * @param kind the rule kind
+     * @param ruleId the rule id
      * @param enable Enables/Disables the rule
      * @param actions Actions to update if not null
      */
-
     suspend fun updatePushRuleActions(kind: RuleKind, ruleId: String, enable: Boolean, actions: List<Action>?)
 
     suspend fun removePushRule(kind: RuleKind, ruleId: String)
@@ -50,8 +51,10 @@ interface PushRuleService {
 
 //    fun fulfilledBingRule(event: Event, rules: List<PushRule>): PushRule?
 
-    fun resolveSenderNotificationPermissionCondition(event: Event,
-                                                     condition: SenderNotificationPermissionCondition): Boolean
+    fun resolveSenderNotificationPermissionCondition(
+            event: Event,
+            condition: SenderNotificationPermissionCondition
+    ): Boolean
 
     interface PushRuleListener {
         fun onEvents(pushEvents: PushEvents)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt
index 6973ff1372a30c0ec25620725e3597707d94f56e..db097fd92c980a4e55e66a20bfeb990690187fb1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt
@@ -47,8 +47,8 @@ class RoomMemberCountCondition(
         val numMembers = room.membershipService().getNumberOfJoinedMembers()
 
         return when (prefix) {
-            "<"  -> numMembers < count
-            ">"  -> numMembers > count
+            "<" -> numMembers < count
+            ">" -> numMembers > count
             "<=" -> numMembers <= count
             ">=" -> numMembers >= count
             else -> numMembers == count
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt
index 1fc8329535460aa9176e6e368b7f4718be8e52c6..ec0936e4c89feb9716f80a8a7b784749f4a9f20b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt
@@ -61,7 +61,7 @@ data class PushCondition(
 
     fun asExecutableCondition(rule: PushRule): Condition? {
         return when (Kind.fromString(kind)) {
-            Kind.EventMatch                   -> {
+            Kind.EventMatch -> {
                 if (key != null && pattern != null) {
                     EventMatchCondition(key, pattern, rule.ruleId == RuleIds.RULE_ID_CONTAIN_USER_NAME)
                 } else {
@@ -69,10 +69,10 @@ data class PushCondition(
                     null
                 }
             }
-            Kind.ContainsDisplayName          -> {
+            Kind.ContainsDisplayName -> {
                 ContainsDisplayNameCondition()
             }
-            Kind.RoomMemberCount              -> {
+            Kind.RoomMemberCount -> {
                 if (iz.isNullOrEmpty()) {
                     Timber.e("Malformed ROOM_MEMBER_COUNT condition")
                     null
@@ -88,7 +88,7 @@ data class PushCondition(
                     SenderNotificationPermissionCondition(key)
                 }
             }
-            Kind.Unrecognised                 -> {
+            Kind.Unrecognised -> {
                 Timber.e("Unknown kind $kind")
                 null
             }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt
index 5bf42b8252a63f4dd258dac3ace31250f79e073e..9498ed002c4db4f9e0bdea12652b5d67f10c0a00 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt
@@ -67,7 +67,7 @@ data class RuleSet(
     /**
      * Find a rule from its rule Id.
      *
-     * @param rules  the rules list.
+     * @param rules the rules list.
      * @param ruleId the rule Id.
      * @return the bing rule if it exists, else null.
      */
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 3a18cf1497ac49f79b228475b0e8ac92c3929cdb..5d2769ac3cbd774c5c78051101ee9b48316673b0 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
@@ -22,6 +22,7 @@ import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataServic
 import org.matrix.android.sdk.api.session.room.alias.AliasService
 import org.matrix.android.sdk.api.session.room.call.RoomCallService
 import org.matrix.android.sdk.api.session.room.crypto.RoomCryptoService
+import org.matrix.android.sdk.api.session.room.location.LocationSharingService
 import org.matrix.android.sdk.api.session.room.members.MembershipService
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.api.session.room.model.relation.RelationService
@@ -163,4 +164,9 @@ interface Room {
      * Get the RoomVersionService associated to this Room.
      */
     fun roomVersionService(): RoomVersionService
+
+    /**
+     * Get the LocationSharingService associated to this Room.
+     */
+    fun locationSharingService(): LocationSharingService
 }
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 cb70603e66cf4c9810b30995b92c055b4bdfc581..77092c4811a302b688402d2ff7d23efb207b7a75 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
@@ -28,8 +28,10 @@ interface RoomDirectoryService {
     /**
      * Get rooms from directory.
      */
-    suspend fun getPublicRooms(server: String?,
-                               publicRoomsParams: PublicRoomsParams): PublicRoomsResponse
+    suspend fun getPublicRooms(
+            server: String?,
+            publicRoomsParams: PublicRoomsParams
+    ): PublicRoomsResponse
 
     /**
      * Get the visibility of a room in the directory.
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 6d5551ddf02d43bfe53e872d4eed8201432626b1..5dfb8961e3ce0fb5a6630c025cde96ca49a64500 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
@@ -60,9 +60,11 @@ interface RoomService {
      * @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.
      */
-    suspend fun joinRoom(roomIdOrAlias: String,
-                         reason: String? = null,
-                         viaServers: List<String> = emptyList())
+    suspend fun joinRoom(
+            roomIdOrAlias: String,
+            reason: String? = null,
+            viaServers: List<String> = emptyList()
+    )
 
     /**
      * @param roomId the roomId of the room to join
@@ -97,19 +99,29 @@ interface RoomService {
      */
     fun getRoomSummary(roomIdOrAlias: String): RoomSummary?
 
+    /**
+     * A live [RoomSummary] associated with the room with id [roomId].
+     * You can observe this summary to get dynamic data from this room, even if the room is not joined yet
+     */
+    fun getRoomSummaryLive(roomId: String): LiveData<Optional<RoomSummary>>
+
     /**
      * Get a snapshot list of room summaries.
      * @return the immutable list of [RoomSummary]
      */
-    fun getRoomSummaries(queryParams: RoomSummaryQueryParams,
-                         sortOrder: RoomSortOrder = RoomSortOrder.NONE): List<RoomSummary>
+    fun getRoomSummaries(
+            queryParams: RoomSummaryQueryParams,
+            sortOrder: RoomSortOrder = RoomSortOrder.NONE
+    ): List<RoomSummary>
 
     /**
      * Get a live list of room summaries. This list is refreshed as soon as the data changes.
      * @return the [LiveData] of List[RoomSummary]
      */
-    fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams,
-                             sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): LiveData<List<RoomSummary>>
+    fun getRoomSummariesLive(
+            queryParams: RoomSummaryQueryParams,
+            sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY
+    ): LiveData<List<RoomSummary>>
 
     /**
      * Get a snapshot list of Breadcrumbs.
@@ -139,8 +151,10 @@ interface RoomService {
     /**
      * Resolve a room alias to a room ID.
      */
-    suspend fun getRoomIdByAlias(roomAlias: String,
-                                 searchOnServer: Boolean): Optional<RoomAliasDescription>
+    suspend fun getRoomIdByAlias(
+            roomAlias: String,
+            searchOnServer: Boolean
+    ): Optional<RoomAliasDescription>
 
     /**
      * Delete a room alias.
@@ -205,16 +219,27 @@ interface RoomService {
     /**
      * TODO Doc.
      */
-    fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
-                                  pagedListConfig: PagedList.Config = defaultPagedListConfig,
-                                  sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): LiveData<PagedList<RoomSummary>>
+    fun getPagedRoomSummariesLive(
+            queryParams: RoomSummaryQueryParams,
+            pagedListConfig: PagedList.Config = defaultPagedListConfig,
+            sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY
+    ): LiveData<PagedList<RoomSummary>>
 
     /**
-     * TODO Doc.
+     * Get's a live paged list from a filter that can be dynamically updated.
+     *
+     * @param queryParams The filter to use
+     * @param pagedListConfig The paged list configuration (page size, initial load, prefetch distance...)
+     * @param sortOrder defines how to sort the results
+     * @param getFlattenParents When true, the list of known parents and grand parents summaries will be resolved.
+     * This can have significant impact on performance, better be used only on manageable list (filtered by displayName, ..).
      */
-    fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
-                                          pagedListConfig: PagedList.Config = defaultPagedListConfig,
-                                          sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): UpdatableLivePageResult
+    fun getFilteredPagedRoomSummariesLive(
+            queryParams: RoomSummaryQueryParams,
+            pagedListConfig: PagedList.Config = defaultPagedListConfig,
+            sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY,
+            getFlattenParents: Boolean = false,
+    ): UpdatableLivePageResult
 
     /**
      * Return a LiveData on the number of rooms.
@@ -240,8 +265,10 @@ interface RoomService {
     /**
      * Returns all the children of this space, as LiveData.
      */
-    fun getFlattenRoomSummaryChildrenOfLive(spaceId: String?,
-                                            memberships: List<Membership> = Membership.activeMemberships()): LiveData<List<RoomSummary>>
+    fun getFlattenRoomSummaryChildrenOfLive(
+            spaceId: String?,
+            memberships: List<Membership> = Membership.activeMemberships()
+    ): LiveData<List<RoomSummary>>
 
     /**
      * Refreshes the RoomSummary LatestPreviewContent for the given @param roomId.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt
index e721abd6a05456e08b315f48924a95a639719d82..9368ad6bf4056e9e9cb50936b475c2087d4b1dc6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt
@@ -16,9 +16,28 @@
 
 package org.matrix.android.sdk.api.session.room
 
+/**
+ * Enum to sort room list.
+ */
 enum class RoomSortOrder {
+    /**
+     * Sort room list by room ascending name.
+     */
     NAME,
+
+    /**
+     * Sort room list by room descending last activity.
+     */
     ACTIVITY,
+
+    /**
+     * Sort room list by room priority and last activity: favorite room first, low priority room last,
+     * then descending last activity.
+     */
     PRIORITY_AND_ACTIVITY,
+
+    /**
+     * Do not sort room list. Useful if the order does not matter. Order can be indeterminate.
+     */
     NONE
 }
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 5c74dcced1be6fe65fdb8024615de874e54cb36a..3d943473e4ebb34aa161bf5847be9cda0088da1c 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
@@ -16,60 +16,99 @@
 
 package org.matrix.android.sdk.api.session.room
 
-import org.matrix.android.sdk.api.query.ActiveSpaceFilter
 import org.matrix.android.sdk.api.query.QueryStringValue
 import org.matrix.android.sdk.api.query.RoomCategoryFilter
 import org.matrix.android.sdk.api.query.RoomTagQueryFilter
+import org.matrix.android.sdk.api.query.SpaceFilter
 import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.model.RoomType
 import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams
 
+/**
+ * Create a [RoomSummaryQueryParams] object, calling [init] with a [RoomSummaryQueryParams.Builder].
+ */
 fun roomSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) = {}): RoomSummaryQueryParams {
-    return RoomSummaryQueryParams.Builder().apply(init).build()
-}
-
-fun spaceSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) = {}): SpaceSummaryQueryParams {
     return RoomSummaryQueryParams.Builder()
             .apply(init)
-            .apply {
-                includeType = listOf(RoomType.SPACE)
-                excludeType = null
-                roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
-            }
             .build()
 }
 
 /**
- * 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].
+ * Create a [SpaceSummaryQueryParams] object (which is a [RoomSummaryQueryParams]), calling [init] with a [RoomSummaryQueryParams.Builder].
+ * This is specific for spaces, other filters will be applied after invoking [init]
+ */
+fun spaceSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) = {}): SpaceSummaryQueryParams {
+    return roomSummaryQueryParams {
+        init()
+        includeType = listOf(RoomType.SPACE)
+        excludeType = null
+        roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
+    }
+}
+
+/**
+ * This class can be used to filter room summaries to use with [RoomService].
+ * It provides a [Builder].
+ * [roomSummaryQueryParams] and [spaceSummaryQueryParams] can also be used to build an instance of this class.
  */
 data class RoomSummaryQueryParams(
-        val roomId: QueryStringValue,
+        /**
+         * Query for the displayName of the room. The display name can be the value of the state event,
+         * or a value returned by [org.matrix.android.sdk.api.RoomDisplayNameFallbackProvider].
+         */
         val displayName: QueryStringValue,
+        /**
+         * Query for the canonical alias of the room.
+         */
         val canonicalAlias: QueryStringValue,
+        /**
+         * Used to filter room by membership.
+         */
         val memberships: List<Membership>,
+        /**
+         * Used to filter room by room category.
+         */
         val roomCategoryFilter: RoomCategoryFilter?,
+        /**
+         * Used to filter room by room tag.
+         */
         val roomTagQueryFilter: RoomTagQueryFilter?,
+        /**
+         * Used to filter room by room type.
+         * @see [includeType]
+         */
         val excludeType: List<String?>?,
+        /**
+         * Used to filter room by room type.
+         * @see [excludeType]
+         */
         val includeType: List<String?>?,
-        val activeSpaceFilter: ActiveSpaceFilter?,
+        /**
+         * Used to filter room using the current space.
+         */
+        val spaceFilter: SpaceFilter?,
+        /**
+         * Used to filter room using the current group.
+         */
         val activeGroupId: String? = null
 ) {
 
+    /**
+     * Builder for [RoomSummaryQueryParams].
+     * [roomSummaryQueryParams] and [spaceSummaryQueryParams] can also be used to build an instance of [RoomSummaryQueryParams].
+     */
     class Builder {
-        var roomId: QueryStringValue = QueryStringValue.IsNotEmpty
-        var displayName: QueryStringValue = QueryStringValue.IsNotEmpty
+        var displayName: QueryStringValue = QueryStringValue.NoCondition
         var canonicalAlias: QueryStringValue = QueryStringValue.NoCondition
         var memberships: List<Membership> = Membership.all()
-        var roomCategoryFilter: RoomCategoryFilter? = RoomCategoryFilter.ALL
+        var roomCategoryFilter: RoomCategoryFilter? = null
         var roomTagQueryFilter: RoomTagQueryFilter? = null
         var excludeType: List<String?>? = listOf(RoomType.SPACE)
         var includeType: List<String?>? = null
-        var activeSpaceFilter: ActiveSpaceFilter = ActiveSpaceFilter.None
+        var spaceFilter: SpaceFilter? = null
         var activeGroupId: String? = null
 
         fun build() = RoomSummaryQueryParams(
-                roomId = roomId,
                 displayName = displayName,
                 canonicalAlias = canonicalAlias,
                 memberships = memberships,
@@ -77,7 +116,7 @@ data class RoomSummaryQueryParams(
                 roomTagQueryFilter = roomTagQueryFilter,
                 excludeType = excludeType,
                 includeType = includeType,
-                activeSpaceFilter = activeSpaceFilter,
+                spaceFilter = spaceFilter,
                 activeGroupId = activeGroupId
         )
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/crypto/RoomCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/crypto/RoomCryptoService.kt
index 6967e0c455026268851987b57839bd86c9f2cea5..606464382005e13a4151e85b85ec7aace6d46142 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/crypto/RoomCryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/crypto/RoomCryptoService.kt
@@ -28,7 +28,8 @@ interface RoomCryptoService {
 
     /**
      * Enable encryption of the room.
-     * @param Use force to ensure that this algorithm will be used. Otherwise this call
+     * @param algorithm the algorithm to set, default to [MXCRYPTO_ALGORITHM_MEGOLM]
+     * @param force Use force to ensure that this algorithm will be used. Otherwise this call
      * will throw if encryption is already setup or if the algorithm is not supported. Only to
      * be used by admins to fix misconfigured encryption.
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/LocationSharingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/LocationSharingService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..dd48d51f45a6a63ce67f4ac143e5581b6e85633c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/LocationSharingService.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.room.location
+
+import androidx.lifecycle.LiveData
+import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
+
+/**
+ * Manage all location sharing related features.
+ */
+interface LocationSharingService {
+    fun getRunningLiveLocationShareSummaries(): LiveData<List<LiveLocationShareAggregatedSummary>>
+}
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 8ef94b28968ee2bdf165883166c21702d1b27653..03298281309dd285e476babbbf9a096dafc0c3c2 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
@@ -95,8 +95,8 @@ data class PowerLevelsContent(
             // the first implementation was a string value
             is String -> value.toInt()
             is Double -> value.toInt()
-            is Int    -> value
-            else      -> Role.Moderator.value
+            is Int -> value
+            else -> Role.Moderator.value
         }
     }
 
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 ba274325bc5b4ff67789a4245c7766886bb5e0cb..7dd853d75d785dda18530866b016252b7f127639 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
@@ -30,9 +30,9 @@ data class RoomGuestAccessContent(
         @Json(name = "guest_access") val guestAccessStr: String? = null
 ) {
     val guestAccess: GuestAccess? = when (guestAccessStr) {
-        "can_join"  -> GuestAccess.CanJoin
+        "can_join" -> GuestAccess.CanJoin
         "forbidden" -> GuestAccess.Forbidden
-        else        -> {
+        else -> {
             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 da5c90ff0534f955b4b30e1fa37c3dfee9b21d32..39b4722c0c5e8953b799d269b590f1778022388d 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
@@ -26,10 +26,10 @@ data class RoomHistoryVisibilityContent(
 ) {
     val historyVisibility: RoomHistoryVisibility? = when (historyVisibilityStr) {
         "world_readable" -> RoomHistoryVisibility.WORLD_READABLE
-        "shared"         -> RoomHistoryVisibility.SHARED
-        "invited"        -> RoomHistoryVisibility.INVITED
-        "joined"         -> RoomHistoryVisibility.JOINED
-        else             -> {
+        "shared" -> RoomHistoryVisibility.SHARED
+        "invited" -> RoomHistoryVisibility.INVITED
+        "joined" -> RoomHistoryVisibility.JOINED
+        else -> {
             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 3b338a36cd0056ee4ad5628c9c8342cf8df59da9..dbe21b16332237ea8beb22aea30f057c2fbd6663 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
@@ -36,12 +36,12 @@ data class RoomJoinRulesContent(
         @Json(name = "allow") val allowList: List<RoomJoinRulesAllowEntry>? = null
 ) {
     val joinRules: RoomJoinRules? = when (joinRulesStr) {
-        "public"     -> RoomJoinRules.PUBLIC
-        "invite"     -> RoomJoinRules.INVITE
-        "knock"      -> RoomJoinRules.KNOCK
-        "private"    -> RoomJoinRules.PRIVATE
+        "public" -> RoomJoinRules.PUBLIC
+        "invite" -> RoomJoinRules.INVITE
+        "knock" -> RoomJoinRules.KNOCK
+        "private" -> RoomJoinRules.PRIVATE
         "restricted" -> RoomJoinRules.RESTRICTED
-        else         -> {
+        else -> {
             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/RoomSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt
index 71c1d8303e5fe567e125d7a17e1747e45ca99d23..1ab23b7a11953b64a104a283c505aa6a1695ed48 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt
@@ -28,65 +28,200 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
  * It can be retrieved by [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService]
  */
 data class RoomSummary(
+        /**
+         * The roomId of the room.
+         */
         val roomId: String,
-        // Computed display name
+        /**
+         * Computed display name. The value of the state event `m.room.name` if not empty, else can be the value returned
+         * by [org.matrix.android.sdk.api.RoomDisplayNameFallbackProvider].
+         */
         val displayName: String = "",
+        /**
+         * The value of the live state event `m.room.name`.
+         */
         val name: String = "",
+        /**
+         * The value of the live state event `m.room.topic`.
+         */
         val topic: String = "",
+        /**
+         * The value of the live state event `m.room.avatar`.
+         */
         val avatarUrl: String = "",
+        /**
+         * The value of the live state event `m.room.canonical_alias`.
+         */
         val canonicalAlias: String? = null,
+        /**
+         * The list of all the aliases of this room. Content of the live state event `m.room.aliases`.
+         */
         val aliases: List<String> = emptyList(),
+        /**
+         * The value of the live state event `m.room.join_rules`.
+         */
         val joinRules: RoomJoinRules? = null,
+        /**
+         * True is this room is referenced in the account data `m.direct`.
+         */
         val isDirect: Boolean = false,
+        /**
+         * If [isDirect] is true, this is the id of the first other member of this room.
+         */
         val directUserId: String? = null,
+        /**
+         * If [isDirect] is true, this it the presence of the first other member of this room.
+         */
         val directUserPresence: UserPresence? = null,
+        /**
+         * Number of members who have joined this room.
+         */
         val joinedMembersCount: Int? = 0,
+        /**
+         * Number of members who are invited to this room.
+         */
         val invitedMembersCount: Int? = 0,
+        /**
+         * Latest [TimelineEvent] which can be displayed in this room. Can be used in the room list.
+         */
         val latestPreviewableEvent: TimelineEvent? = null,
+        /**
+         * List of other member ids of this room.
+         */
         val otherMemberIds: List<String> = emptyList(),
+        /**
+         * Number of unread message in this room.
+         */
         val notificationCount: Int = 0,
+        /**
+         * Number of unread and highlighted message in this room.
+         */
         val highlightCount: Int = 0,
+        /**
+         * True if this room has unread messages.
+         */
         val hasUnreadMessages: Boolean = false,
+        /**
+         * List of tags in this room.
+         */
         val tags: List<RoomTag> = emptyList(),
+        /**
+         * Current user membership in this room.
+         */
         val membership: Membership = Membership.NONE,
+        /**
+         * Versioning state of this room.
+         */
         val versioningState: VersioningState = VersioningState.NONE,
+        /**
+         * Value of `m.fully_read` for this room.
+         */
         val readMarkerId: String? = null,
+        /**
+         * Message saved as draft for this room.
+         */
         val userDrafts: List<UserDraft> = emptyList(),
+        /**
+         * True if this room is encrypted.
+         */
         val isEncrypted: Boolean,
+        /**
+         * Timestamp of the `m.room.encryption` state event.
+         */
         val encryptionEventTs: Long?,
+        /**
+         * List of users who are currently typing on this room.
+         */
         val typingUsers: List<SenderInfo>,
+        /**
+         * UserId of the user who has invited the current user to this room.
+         */
         val inviterId: String? = null,
+        /**
+         * Breadcrumb index, util to sort rooms by last seen.
+         */
         val breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS,
+        /**
+         * The room encryption trust level.
+         * @see [RoomEncryptionTrustLevel]
+         */
         val roomEncryptionTrustLevel: RoomEncryptionTrustLevel? = null,
+        /**
+         * True if a message has not been sent in this room.
+         */
         val hasFailedSending: Boolean = false,
+        /**
+         * The type of the room. Null for regular room.
+         * @see [RoomType]
+         */
         val roomType: String? = null,
+        /**
+         * List of parent spaces.
+         */
         val spaceParents: List<SpaceParentInfo>? = null,
+        /**
+         * List of children space.
+         */
         val spaceChildren: List<SpaceChildInfo>? = null,
+        /**
+         * List of all the space parents. Will be empty by default, you have to explicitly request it.
+         */
+        val flattenParents: List<RoomSummary> = emptyList(),
+        /**
+         * List of all the space parent Ids.
+         */
         val flattenParentIds: List<String> = emptyList(),
-        val roomEncryptionAlgorithm: RoomEncryptionAlgorithm? = null
+        /**
+         * Information about the encryption algorithm, if this room is encrypted.
+         */
+        val roomEncryptionAlgorithm: RoomEncryptionAlgorithm? = null,
 ) {
-
+    /**
+     * True if [versioningState] is not [VersioningState.NONE].
+     */
     val isVersioned: Boolean
         get() = versioningState != VersioningState.NONE
 
+    /**
+     * True if [notificationCount] is not `0`.
+     */
     val hasNewMessages: Boolean
         get() = notificationCount != 0
 
+    /**
+     * True if the room has the tag `m.lowpriority`.
+     */
     val isLowPriority: Boolean
         get() = hasTag(RoomTag.ROOM_TAG_LOW_PRIORITY)
 
+    /**
+     * True if the room has the tag `m.favourite`.
+     */
     val isFavorite: Boolean
         get() = hasTag(RoomTag.ROOM_TAG_FAVOURITE)
 
+    /**
+     * True if [joinRules] is [RoomJoinRules.PUBLIC].
+     */
     val isPublic: Boolean
         get() = joinRules == RoomJoinRules.PUBLIC
 
+    /**
+     * Test if the room has the provided [tag].
+     */
     fun hasTag(tag: String) = tags.any { it.name == tag }
 
+    /**
+     * True if a 1-1 call can be started, i.e. the room has exactly 2 joined members.
+     */
     val canStartCall: Boolean
         get() = joinedMembersCount == 2
 
     companion object {
+        /**
+         * Constant to indicated that the room is not on the breadcrumbs.
+         * Used by [breadcrumbsIndex].
+         */
         const val NOT_IN_BREADCRUMBS = -1
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/VersioningState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/VersioningState.kt
index b4e7b10d4451c1627011d3267117b0319487bfe5..2e1668ebbba7f8a7dad45d9c0073ec8d6e0a6823 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/VersioningState.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/VersioningState.kt
@@ -16,8 +16,22 @@
 
 package org.matrix.android.sdk.api.session.room.model
 
+/**
+ * Enum for the versioning state of a room.
+ */
 enum class VersioningState {
+    /**
+     * The room is not versioned.
+     */
     NONE,
+
+    /**
+     * The room has been upgraded, but the new room is not joined yet.
+     */
     UPGRADED_ROOM_NOT_JOINED,
-    UPGRADED_ROOM_JOINED
+
+    /**
+     * The room has been upgraded, and the new room has been joined.
+     */
+    UPGRADED_ROOM_JOINED,
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationShareAggregatedSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationShareAggregatedSummary.kt
index 0b28d62f56b8d0ae02856d248a5272c6db131732..5ad1a482174d5888caf56ca47c80800d83d2f9c5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationShareAggregatedSummary.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationShareAggregatedSummary.kt
@@ -22,6 +22,10 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocati
  * Aggregation info concerning a live location share.
  */
 data class LiveLocationShareAggregatedSummary(
+        val userId: String?,
+        /**
+         * Indicate whether the live is currently running.
+         */
         val isActive: Boolean?,
         val endOfLiveTimestampMillis: Long?,
         val lastLocationDataContent: MessageBeaconLocationDataContent?,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVerificationAcceptContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVerificationAcceptContent.kt
index 27619cf0a91db1a78e0ede5bd333f24bf4c474f9..33f61648dcb97fd1de1573e8d857368116156d50 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVerificationAcceptContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVerificationAcceptContent.kt
@@ -40,12 +40,14 @@ internal data class MessageVerificationAcceptContent(
 
     companion object : VerificationInfoAcceptFactory {
 
-        override fun create(tid: String,
-                            keyAgreementProtocol: String,
-                            hash: String,
-                            commitment: String,
-                            messageAuthenticationCode: String,
-                            shortAuthenticationStrings: List<String>): VerificationInfoAccept {
+        override fun create(
+                tid: String,
+                keyAgreementProtocol: String,
+                hash: String,
+                commitment: String,
+                messageAuthenticationCode: String,
+                shortAuthenticationStrings: List<String>
+        ): VerificationInfoAccept {
             return MessageVerificationAcceptContent(
                     hash,
                     keyAgreementProtocol,
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 0d094b835b3066a61df8299a46b7f9eea5c9074c..d34ea3c7d3658780e9b176d622957c9e7f2c1950 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
@@ -58,40 +58,50 @@ interface RelationService {
      * @param targetEventId the id of the event being reacted
      * @param reaction the reaction (preferably emoji)
      */
-    fun sendReaction(targetEventId: String,
-                     reaction: String): Cancelable
+    fun sendReaction(
+            targetEventId: String,
+            reaction: String
+    ): Cancelable
 
     /**
      * Undo a reaction (emoji) to the targetedEvent.
      * @param targetEventId the id of the event being reacted
      * @param reaction the reaction (preferably emoji)
      */
-    suspend fun undoReaction(targetEventId: String,
-                             reaction: String): Cancelable
+    suspend fun undoReaction(
+            targetEventId: String,
+            reaction: String
+    ): Cancelable
 
     /**
      * Edit a poll.
-     * @param pollType indicates open or closed polls
      * @param targetEvent The poll event to edit
+     * @param pollType indicates open or closed polls
      * @param question The edited question
      * @param options The edited options
      */
-    fun editPoll(targetEvent: TimelineEvent,
-                 pollType: PollType,
-                 question: String,
-                 options: List<String>): Cancelable
+    fun editPoll(
+            targetEvent: TimelineEvent,
+            pollType: PollType,
+            question: String,
+            options: List<String>
+    ): Cancelable
 
     /**
      * Edit a text message body. Limited to "m.text" contentType.
      * @param targetEvent The event to edit
+     * @param msgType the message type
      * @param newBodyText The edited body
+     * @param newBodyAutoMarkdown true to parse markdown on the new body
      * @param compatibilityBodyText The text that will appear on clients that don't support yet edition
      */
-    fun editTextMessage(targetEvent: TimelineEvent,
-                        msgType: String,
-                        newBodyText: CharSequence,
-                        newBodyAutoMarkdown: Boolean,
-                        compatibilityBodyText: String = "* $newBodyText"): Cancelable
+    fun editTextMessage(
+            targetEvent: TimelineEvent,
+            msgType: String,
+            newBodyText: CharSequence,
+            newBodyAutoMarkdown: Boolean,
+            compatibilityBodyText: String = "* $newBodyText"
+    ): Cancelable
 
     /**
      * Edit a reply. This is a special case because replies contains fallback text as a prefix.
@@ -101,10 +111,12 @@ interface RelationService {
      * @param newBodyText The edited body (stripped from in reply to content)
      * @param compatibilityBodyText The text that will appear on clients that don't support yet edition
      */
-    fun editReply(replyToEdit: TimelineEvent,
-                  originalTimelineEvent: TimelineEvent,
-                  newBodyText: String,
-                  compatibilityBodyText: String = "* $newBodyText"): Cancelable
+    fun editReply(
+            replyToEdit: TimelineEvent,
+            originalTimelineEvent: TimelineEvent,
+            newBodyText: String,
+            compatibilityBodyText: String = "* $newBodyText"
+    ): Cancelable
 
     /**
      * Get the edit history of the given event.
@@ -125,11 +137,12 @@ interface RelationService {
      * @param showInThread If true, relation will be added to the reply in order to be visible from within threads
      * @param rootThreadEventId If show in thread is true then we need the rootThreadEventId to generate the relation
      */
-    fun replyToMessage(eventReplied: TimelineEvent,
-                       replyText: CharSequence,
-                       autoMarkdown: Boolean = false,
-                       showInThread: Boolean = false,
-                       rootThreadEventId: String? = null
+    fun replyToMessage(
+            eventReplied: TimelineEvent,
+            replyText: CharSequence,
+            autoMarkdown: Boolean = false,
+            showInThread: Boolean = false,
+            rootThreadEventId: String? = null
     ): Cancelable?
 
     /**
@@ -153,14 +166,16 @@ interface RelationService {
      * @param rootThreadEventId the root thread eventId
      * @param replyInThreadText the reply text
      * @param msgType the message type: MessageType.MSGTYPE_TEXT (default) or MessageType.MSGTYPE_EMOTE
-     * @param formattedText The formatted body using MessageType#FORMAT_MATRIX_HTML
      * @param autoMarkdown If true, the SDK will generate a formatted HTML message from the body text if markdown syntax is present
+     * @param formattedText The formatted body using MessageType#FORMAT_MATRIX_HTML
      * @param eventReplied the event referenced by the reply within a thread
      */
-    fun replyInThread(rootThreadEventId: String,
-                      replyInThreadText: CharSequence,
-                      msgType: String = MessageType.MSGTYPE_TEXT,
-                      autoMarkdown: Boolean = false,
-                      formattedText: String? = null,
-                      eventReplied: TimelineEvent? = null): Cancelable?
+    fun replyInThread(
+            rootThreadEventId: String,
+            replyInThreadText: CharSequence,
+            msgType: String = MessageType.MSGTYPE_TEXT,
+            autoMarkdown: Boolean = false,
+            formattedText: String? = null,
+            eventReplied: TimelineEvent? = null
+    ): Cancelable?
 }
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 165a912b7fac0ed9898d38a45abf872b92938500..36993074aafe6305beb500061a640edbf2634da9 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
@@ -58,7 +58,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
     /**
      * Tell if an user can send an event of a certain type.
      *
-     * @param userId  the id of the user to check for.
+     * @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)
      * @param eventType the event type to check for
      * @return true if the user can send this type of event
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt
index 5fe9bf6993a6c0afde6470782e8c0a3aca69269c..c5cc573458118de0d3d03989084e06465f71443c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt
@@ -32,11 +32,11 @@ sealed class Role(open val value: Int) : Comparable<Role> {
         // Order matters, default value should be checked after defined roles
         fun fromValue(value: Int, default: Int): Role {
             return when (value) {
-                Admin.value     -> Admin
+                Admin.value -> Admin
                 Moderator.value -> Moderator
                 Default.value,
-                default         -> Default
-                else            -> Custom(value)
+                default -> Default
+                else -> Custom(value)
             }
         }
     }
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 036628c02f53151ce68f2f9fdad1529ecb509539..dac1a1a773e5c28e73c2083a2ad6799712569462 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
@@ -71,7 +71,7 @@ interface ReadService {
 
     /**
      * Returns a live list of read receipts for a given event.
-     * @param eventId: the 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/SendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt
index 4bb8abef8aaaff9c1b2292b10857a8799de9e4a5..661c3be5bd01a703d70bcba346b44f853e50bc54 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
@@ -62,6 +62,7 @@ interface SendService {
      * @param quotedEvent The event to which we will quote it's content.
      * @param text the text message to send
      * @param autoMarkdown If true, the SDK will generate a formatted HTML message from the body text if markdown syntax is present
+     * @param rootThreadEventId when this param is not null, the message will be sent in this specific thread
      * @return a [Cancelable]
      */
     fun sendQuotedTextMessage(quotedEvent: TimelineEvent, text: String, autoMarkdown: Boolean, rootThreadEventId: String? = null): Cancelable
@@ -75,10 +76,12 @@ interface SendService {
      * @param rootThreadEventId when this param is not null, the Media will be sent in this specific thread
      * @return a [Cancelable]
      */
-    fun sendMedia(attachment: ContentAttachmentData,
-                  compressBeforeSending: Boolean,
-                  roomIds: Set<String>,
-                  rootThreadEventId: String? = null): Cancelable
+    fun sendMedia(
+            attachment: ContentAttachmentData,
+            compressBeforeSending: Boolean,
+            roomIds: Set<String>,
+            rootThreadEventId: String? = null
+    ): Cancelable
 
     /**
      * Method to send a list of media asynchronously.
@@ -89,10 +92,12 @@ interface SendService {
      * @param rootThreadEventId when this param is not null, all the Media will be sent in this specific thread
      * @return a [Cancelable]
      */
-    fun sendMedias(attachments: List<ContentAttachmentData>,
-                   compressBeforeSending: Boolean,
-                   roomIds: Set<String>,
-                   rootThreadEventId: String? = null): Cancelable
+    fun sendMedias(
+            attachments: List<ContentAttachmentData>,
+            compressBeforeSending: Boolean,
+            roomIds: Set<String>,
+            rootThreadEventId: String? = null
+    ): Cancelable
 
     /**
      * Send a poll to the room.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendState.kt
index 7c806bf35b5634b032f418f4ee3479f32d67b65e..d058ff2840c44da3e0dbf0df639e17a2b897daa2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendState.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendState.kt
@@ -17,27 +17,44 @@
 package org.matrix.android.sdk.api.session.room.send
 
 enum class SendState {
+    /**
+     * The state is unknown.
+     */
     UNKNOWN,
 
-    // the event has not been sent
+    /**
+     * The event has not been sent.
+     */
     UNSENT,
 
-    // the event is encrypting
+    /**
+     * The event is encrypting.
+     */
     ENCRYPTING,
 
-    // the event is currently sending
+    /**
+     * The event is currently sending.
+     */
     SENDING,
 
-    // the event has been sent
+    /**
+     * The event has been sent.
+     */
     SENT,
 
-    // the event has been received from server
+    /**
+     * The event has been received from server.
+     */
     SYNCED,
 
-    // The event failed to be sent
+    /**
+     * The event failed to be sent.
+     */
     UNDELIVERED,
 
-    // the event failed to be sent because some unknown devices have been found while encrypting it
+    /**
+     * The event failed to be sent because some unknown devices have been found while encrypting it.
+     */
     FAILED_UNKNOWN_DEVICES;
 
     internal companion object {
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 4ede1a66fc53a755917f0a493c16037fad70f400..e16405b3c08e806fcae6b8f13a16a819709c481c 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
@@ -33,7 +33,7 @@ sealed interface UserDraft {
     fun isValid(): Boolean {
         return when (this) {
             is Regular -> content.isNotBlank()
-            else       -> true
+            else -> true
         }
     }
 }
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 4c308c355a02163f30f533fb221c027b85364a47..d629df8b166965cd7892606a4a846af2433b7ac2 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
@@ -29,9 +29,9 @@ data class SenderInfo(
 ) {
     val disambiguatedDisplayName: String
         get() = when {
-            displayName == null                       -> userId
+            displayName == null -> userId
             displayName.replaceSpaceChars().isBlank() -> "$displayName ($userId)"
-            isUniqueDisplayName                       -> displayName
-            else                                      -> "$displayName ($userId)"
+            isUniqueDisplayName -> displayName
+            else -> "$displayName ($userId)"
         }
 }
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 f6b56128d39aa8782e254550b8ecfc0d52f4b3f9..c79171f1564cb0e6c7960f9fd4b6080e806f2240 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
@@ -90,23 +90,29 @@ interface StateService {
 
     /**
      * Get a state event of the room.
+     * @param eventType An eventType.
+     * @param stateKey the query which will be done on the stateKey
      */
     fun getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event?
 
     /**
      * Get a live state event of the room.
+     * @param eventType An eventType.
+     * @param stateKey the query which will be done on the stateKey
      */
     fun getStateEventLive(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): LiveData<Optional<Event>>
 
     /**
      * Get state events of the room.
      * @param eventTypes Set of eventType. If empty, all state events will be returned
+     * @param stateKey the query which will be done on the stateKey
      */
     fun getStateEvents(eventTypes: Set<String>, stateKey: QueryStringValue = QueryStringValue.NoCondition): List<Event>
 
     /**
      * Get live state events of the room.
      * @param eventTypes Set of eventType to observe. If empty, all state events will be observed
+     * @param stateKey the query which will be done on the stateKey
      */
     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/threads/model/ThreadEditions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadEditions.kt
index c8353cf0de0c7255aae7472e55b0eda99653eb3c..dc9cc886e9c4ed358bfef3c44655de2968024e99 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadEditions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadEditions.kt
@@ -16,5 +16,7 @@
 
 package org.matrix.android.sdk.api.session.room.threads.model
 
-data class ThreadEditions(var rootThreadEdition: String? = null,
-                          var latestThreadEdition: String? = null)
+data class ThreadEditions(
+        var rootThreadEdition: String? = null,
+        var latestThreadEdition: String? = null
+)
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 1ef972e889be030601c086df4d0ecff7a5249839..0b1aea1966a8404e72e4edfa9ab48d3d45e7864a 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
@@ -22,12 +22,14 @@ import org.matrix.android.sdk.api.session.room.sender.SenderInfo
 /**
  * The main thread Summary model, mainly used to display the thread list.
  */
-data class ThreadSummary(val roomId: String,
-                         val rootEvent: Event?,
-                         val latestEvent: Event?,
-                         val rootEventId: String,
-                         val rootThreadSenderInfo: SenderInfo,
-                         val latestThreadSenderInfo: SenderInfo,
-                         val isUserParticipating: Boolean,
-                         val numberOfThreads: Int,
-                         val threadEditions: ThreadEditions = ThreadEditions())
+data class ThreadSummary(
+        val roomId: String,
+        val rootEvent: Event?,
+        val latestEvent: Event?,
+        val rootEventId: String,
+        val rootThreadSenderInfo: SenderInfo,
+        val latestThreadSenderInfo: SenderInfo,
+        val isUserParticipating: Boolean,
+        val numberOfThreads: Int,
+        val threadEditions: ThreadEditions = ThreadEditions()
+)
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 b87bc25435cc249858ca133f763d2cce042e5c0c..9d8c8a13bd7aafaa44df96aff0c645550ba3fd40 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
@@ -30,6 +30,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel
 import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
 import org.matrix.android.sdk.api.session.room.model.ReadReceipt
 import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
+import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageContent
 import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
@@ -89,6 +90,7 @@ data class TimelineEvent(
 
     /**
      * Get the metadata associated with a key.
+     * @param T type to cast the metadata to
      * @param key the key to get the metadata
      * @return the metadata
      */
@@ -137,10 +139,11 @@ fun TimelineEvent.getEditedEventId(): String? {
  */
 fun TimelineEvent.getLastMessageContent(): MessageContent? {
     return when (root.getClearType()) {
-        EventType.STICKER                   -> root.getClearContent().toModel<MessageStickerContent>()
-        in EventType.POLL_START             -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessagePollContent>()
+        EventType.STICKER -> root.getClearContent().toModel<MessageStickerContent>()
+        in EventType.POLL_START -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessagePollContent>()
         in EventType.STATE_ROOM_BEACON_INFO -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessageBeaconInfoContent>()
-        else                                -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel()
+        in EventType.BEACON_LOCATION_DATA -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessageBeaconLocationDataContent>()
+        else -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel()
     }
 }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt
index bc1c9e57694ad23d2e1f7fd2b085629178dce161..ffb8b1ca4dae0441bcd0a7fb73fd8fa9eec29983 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt
@@ -33,12 +33,14 @@ interface SearchService {
      * @param afterLimit how many events after the result are returned.
      * @param includeProfile requests that the server returns the historic profile information for the users that sent the events that were returned.
      */
-    suspend fun search(searchTerm: String,
-                       roomId: String,
-                       nextBatch: String?,
-                       orderByRecent: Boolean,
-                       limit: Int,
-                       beforeLimit: Int,
-                       afterLimit: Int,
-                       includeProfile: Boolean): SearchResult
+    suspend fun search(
+            searchTerm: String,
+            roomId: String,
+            nextBatch: String?,
+            orderByRecent: Boolean,
+            limit: Int,
+            beforeLimit: Int,
+            afterLimit: Int,
+            includeProfile: Boolean
+    ): SearchResult
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/ActiveSpaceFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/KeyRef.kt
similarity index 64%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/ActiveSpaceFilter.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/KeyRef.kt
index 48619b9394bb85ba20700c3a9f63147ee750c64f..5a1bf67fdde108639fa2854b112936dbba01e04d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/ActiveSpaceFilter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/KeyRef.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 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,10 +14,9 @@
  * limitations under the License.
  */
 
-package org.matrix.android.sdk.api.query
+package org.matrix.android.sdk.api.session.securestorage
 
-sealed class ActiveSpaceFilter {
-    object None : ActiveSpaceFilter()
-    data class ActiveSpace(val currentSpaceId: String?) : ActiveSpaceFilter()
-    data class ExcludeSpace(val spaceId: String) : ActiveSpaceFilter()
-}
+data class KeyRef(
+        val keyId: String?,
+        val keySpec: SsssKeySpec?
+)
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 528e07196693656b73440350bd77f8795c01b0b7..bdbbd3ea846cbf4b4f3235090d60b08fceaa06b4 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
@@ -44,10 +44,12 @@ interface SharedSecretStorageService {
      *
      * @return key creation info
      */
-    suspend fun generateKey(keyId: String,
-                            key: SsssKeySpec?,
-                            keyName: String,
-                            keySigner: KeySigner?): SsssKeyCreationInfo
+    suspend fun generateKey(
+            keyId: String,
+            key: SsssKeySpec?,
+            keyName: String,
+            keySigner: KeySigner?
+    ): SsssKeyCreationInfo
 
     /**
      * Generates a SSSS key using the given passphrase.
@@ -61,11 +63,13 @@ interface SharedSecretStorageService {
      *
      * @return key creation info
      */
-    suspend fun generateKeyWithPassphrase(keyId: String,
-                                          keyName: String,
-                                          passphrase: String,
-                                          keySigner: KeySigner,
-                                          progressListener: ProgressListener?): SsssKeyCreationInfo
+    suspend fun generateKeyWithPassphrase(
+            keyId: String,
+            keyName: String,
+            passphrase: String,
+            keySigner: KeySigner,
+            progressListener: ProgressListener?
+    ): SsssKeyCreationInfo
 
     fun getKey(keyId: String): KeyInfoResult
 
@@ -92,7 +96,7 @@ interface SharedSecretStorageService {
      * Clients MUST ensure that the key is trusted before using it to encrypt secrets.
      *
      * @param name The name of the secret
-     * @param secret The secret contents.
+     * @param secretBase64 The secret contents.
      * @param keys The list of (ID,privateKey) of the keys to use to encrypt the secret.
      */
     suspend fun storeSecret(name: String, secretBase64: String, keys: List<KeyRef>)
@@ -132,9 +136,4 @@ interface SharedSecretStorageService {
     fun checkShouldBeAbleToAccessSecrets(secretNames: List<String>, keyId: String?): IntegrityResult
 
     suspend fun requestSecret(name: String, myOtherDeviceId: String)
-
-    data class KeyRef(
-            val keyId: String?,
-            val keySpec: SsssKeySpec?
-    )
 }
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 c9903886285c8349e396fa784bccd311cbe31a31..61c03e08fcd56f53b6eb2f5b72d159a17a74cb3c 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
@@ -31,11 +31,13 @@ interface Space {
      */
     fun spaceSummary(): RoomSummary?
 
-    suspend fun addChildren(roomId: String,
-                            viaServers: List<String>?,
-                            order: String?,
+    suspend fun addChildren(
+            roomId: String,
+            viaServers: List<String>?,
+            order: String?,
 //                            autoJoin: Boolean = false,
-                            suggested: Boolean? = false)
+            suggested: Boolean? = false
+    )
 
     fun getChildInfo(roomId: String): SpaceChildContent?
 
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 8f16b3b9c3fb7c711403af61b1feb9c67bbc341e..c7a64050146be35ae42b3cb5c663c4a625948337 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
@@ -37,15 +37,17 @@ interface SpaceService {
     /**
      * Just a shortcut for space creation for ease of use.
      */
-    suspend fun createSpace(name: String,
-                            topic: String?,
-                            avatarUri: Uri?,
-                            isPublic: Boolean,
-                            roomAliasLocalPart: String? = null): String
+    suspend fun createSpace(
+            name: String,
+            topic: String?,
+            avatarUri: Uri?,
+            isPublic: Boolean,
+            roomAliasLocalPart: String? = null
+    ): String
 
     /**
-     * Get a space from a roomId.
-     * @param spaceId the roomId to look for.
+     * Get a space from a spaceId.
+     * @param spaceId the spaceId to look for.
      * @return a space with spaceId or null if room type is not space
      */
     fun getSpace(spaceId: String): Space?
@@ -54,36 +56,47 @@ interface SpaceService {
      * Try to resolve (peek) rooms and subspace in this space.
      * Use this call get preview of children of this space, particularly useful to get a
      * preview of rooms that you did not join yet.
+     * @param spaceId the spaceId to look for.
      */
     suspend fun peekSpace(spaceId: String): SpacePeekResult
 
     /**
      * Get's information of a space by querying the server.
+     *
+     * @param spaceId the spaceId to look for.
      * @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,
+     * @param from Optional. Pagination token given to retrieve the next set of rooms. Note that if a pagination token is provided,
      * then the parameters given for suggested_only and max_depth must be the same.
+     * @param knownStateList when paginating, pass back the m.space.child state events
      */
-    suspend fun querySpaceChildren(spaceId: String,
-                                   suggestedOnly: Boolean? = null,
-                                   limit: Int? = null,
-                                   from: String? = null,
-            // when paginating, pass back the m.space.child state events
-                                   knownStateList: List<Event>? = null): SpaceHierarchyData
+    suspend fun querySpaceChildren(
+            spaceId: String,
+            suggestedOnly: Boolean? = null,
+            limit: Int? = null,
+            from: String? = null,
+            knownStateList: List<Event>? = null
+    ): SpaceHierarchyData
 
     /**
      * Get a live list of space summaries. This list is refreshed as soon as the data changes.
      * @return the [LiveData] of List[SpaceSummary]
      */
-    fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams,
-                              sortOrder: RoomSortOrder = RoomSortOrder.NONE): LiveData<List<RoomSummary>>
-
-    fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams,
-                          sortOrder: RoomSortOrder = RoomSortOrder.NONE): List<RoomSummary>
-
-    suspend fun joinSpace(spaceIdOrAlias: String,
-                          reason: String? = null,
-                          viaServers: List<String> = emptyList()): JoinSpaceResult
+    fun getSpaceSummariesLive(
+            queryParams: SpaceSummaryQueryParams,
+            sortOrder: RoomSortOrder = RoomSortOrder.NONE
+    ): LiveData<List<RoomSummary>>
+
+    fun getSpaceSummaries(
+            spaceSummaryQueryParams: SpaceSummaryQueryParams,
+            sortOrder: RoomSortOrder = RoomSortOrder.NONE
+    ): List<RoomSummary>
+
+    suspend fun joinSpace(
+            spaceIdOrAlias: String,
+            reason: String? = null,
+            viaServers: List<String> = emptyList()
+    ): JoinSpaceResult
 
     suspend fun rejectInvite(spaceId: String, reason: String?)
 
@@ -98,7 +111,10 @@ interface SpaceService {
 
     /**
      * Let this room declare that it has a parent.
+     * @param childRoomId the space to set as a child
+     * @param parentSpaceId the parentId which will be set
      * @param canonical true if it should be the main parent of this room
+     * @param viaServers list of candidate servers that can be used to set the parent
      * In practice, well behaved rooms should only have one canonical parent, but given this is not enforced:
      * if multiple are present the client should select the one with the lowest room ID, as determined via a lexicographic utf-8 ordering.
      */
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 76755517ce25546e14c201be3880e94eb9e96b46..d9c77723936186358d3d5288db4695d74f913ae6 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
@@ -23,15 +23,19 @@ sealed interface StatisticEvent {
     /**
      * Initial sync request, response downloading, and treatment (parsing and storage) of response.
      */
-    data class InitialSyncRequest(val requestDurationMs: Int,
-                                  val downloadDurationMs: Int,
-                                  val treatmentDurationMs: Int,
-                                  val nbOfJoinedRooms: Int) : StatisticEvent
+    data class InitialSyncRequest(
+            val requestDurationMs: Int,
+            val downloadDurationMs: Int,
+            val treatmentDurationMs: Int,
+            val nbOfJoinedRooms: Int
+    ) : StatisticEvent
 
     /**
      * Incremental sync event.
      */
-    data class SyncTreatment(val durationMs: Int,
-                             val afterPause: Boolean,
-                             val nbOfJoinedRooms: Int) : StatisticEvent
+    data class SyncTreatment(
+            val durationMs: Int,
+            val afterPause: Boolean,
+            val nbOfJoinedRooms: Int
+    ) : StatisticEvent
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitSyncStep.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStep.kt
similarity index 91%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitSyncStep.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStep.kt
index 901c1b2ffbc756fee00d912d7c2eb51e3523b840..407585b003c448b3eb1b246d11df009982b37efd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitSyncStep.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStep.kt
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package org.matrix.android.sdk.api.session.initsync
+package org.matrix.android.sdk.api.session.sync
 
-enum class InitSyncStep {
+enum class InitialSyncStep {
     ServerComputing,
     Downloading,
     ImportingAccount,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncRequestState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncRequestState.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4e932d49de85f04a16399b7a8bcd21ff9a2ab167
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncRequestState.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.sync
+
+sealed interface SyncRequestState {
+    /**
+     * For initial sync.
+     */
+    interface InitialSyncRequestState : SyncRequestState
+
+    object Idle : InitialSyncRequestState
+    data class InitialSyncProgressing(
+            val initialSyncStep: InitialSyncStep,
+            val percentProgress: Int = 0
+    ) : InitialSyncRequestState
+
+    /**
+     * For incremental sync.
+     */
+    interface IncrementalSyncRequestState : SyncRequestState
+
+    object IncrementalSyncIdle : IncrementalSyncRequestState
+    data class IncrementalSyncParsing(
+            val rooms: Int,
+            val toDevice: Int
+    ) : IncrementalSyncRequestState
+
+    object IncrementalSyncError : IncrementalSyncRequestState
+    object IncrementalSyncDone : IncrementalSyncRequestState
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5b2bf651af891090d6776600d19dc16ddd29282a
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.sync
+
+import androidx.lifecycle.LiveData
+import kotlinx.coroutines.flow.SharedFlow
+import org.matrix.android.sdk.api.session.sync.model.SyncResponse
+
+interface SyncService {
+    /**
+     * This method start the sync thread.
+     */
+    fun startSync(fromForeground: Boolean)
+
+    /**
+     * This method stop the sync thread.
+     */
+    fun stopSync()
+
+    /**
+     * Requires a one time background sync.
+     */
+    fun requireBackgroundSync()
+
+    /**
+     * Launches infinite self rescheduling background syncs via the WorkManager.
+     *
+     * 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.
+     */
+    fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long)
+
+    fun stopAnyBackgroundSync()
+
+    /**
+     * This method returns the current sync state.
+     * @return the current [SyncState].
+     */
+    fun getSyncState(): SyncState
+
+    /**
+     * This method allows to listen the sync state.
+     * @return a [LiveData] of [SyncState].
+     */
+    fun getSyncStateLive(): LiveData<SyncState>
+
+    /**
+     * Get the [SyncRequestState] as a LiveData.
+     */
+    fun getSyncRequestStateLive(): LiveData<SyncRequestState>
+
+    /**
+     * This method returns a flow of SyncResponse. New value will be pushed through the sync thread.
+     */
+    fun syncFlow(): SharedFlow<SyncResponse>
+
+    /**
+     * This methods return true if an initial sync has been processed.
+     */
+    fun hasAlreadySynced(): Boolean
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncAndroidService.kt
similarity index 97%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncService.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncAndroidService.kt
index ac81be2174b2234a359830f154ab8a9deb3227d3..8dee633b9c18555ecc02f63340af9283e15ced5a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncAndroidService.kt
@@ -46,7 +46,7 @@ import java.util.concurrent.atomic.AtomicBoolean
  * in order to be able to perform a sync even if the app is not running.
  * The <receiver> and <service> must be declared in the Manifest or the app using the SDK
  */
-abstract class SyncService : Service() {
+abstract class SyncAndroidService : Service() {
 
     private var sessionId: String? = null
     private var mIsSelfDestroyed: Boolean = false
@@ -84,7 +84,7 @@ abstract class SyncService : Service() {
                     stopMe()
                 }
             }
-            else        -> {
+            else -> {
                 val isInit = initialize(intent)
                 onStart(isInitialSync)
                 if (isInit) {
@@ -158,9 +158,9 @@ abstract class SyncService : Service() {
             // never do that in foreground, let the syncThread work
             syncTask.execute(params)
             // Start sync if we were doing an initial sync and the syncThread is not launched yet
-            if (isInitialSync && session.getSyncState() == SyncState.Idle) {
+            if (isInitialSync && session.syncService().getSyncState() == SyncState.Idle) {
                 val isForeground = !backgroundDetectionObserver.isInBackground
-                session.startSync(isForeground)
+                session.syncService().startSync(isForeground)
             }
             stopMe()
         } catch (throwable: Throwable) {
@@ -210,7 +210,7 @@ abstract class SyncService : Service() {
             session = sessionComponent.session()
             sessionId = safeSessionId
             syncTask = sessionComponent.syncTask()
-            isInitialSync = !session.hasAlreadySynced()
+            isInitialSync = !session.syncService().hasAlreadySynced()
             networkConnectivityChecker = sessionComponent.networkConnectivityChecker()
             taskExecutor = sessionComponent.taskExecutor()
             coroutineDispatchers = sessionComponent.coroutineDispatchers()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncUnreadNotifications.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncUnreadNotifications.kt
index 6618bceacd9327ff357a194623bc7d1191b03778..09273f56e63089e59901f269862ca467df181a5e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncUnreadNotifications.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncUnreadNotifications.kt
@@ -38,4 +38,5 @@ data class RoomSyncUnreadNotifications(
         /**
          * The number of highlighted unread messages (subset of notifications).
          */
-        @Json(name = "highlight_count") val highlightCount: Int? = null)
+        @Json(name = "highlight_count") val highlightCount: Int? = null
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsResponse.kt
index 9a30b4d764d26812d2784ee1e686e6742f4a3a60..ae728326ccdd9cef016f94a56e061416b3e4f84e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsResponse.kt
@@ -30,8 +30,10 @@ data class TermsResponse(
         val policies: JsonDict? = null
 ) {
 
-    fun getLocalizedTerms(userLanguage: String,
-                          defaultLanguage: String = "en"): List<LocalizedFlowDataLoginTerms> {
+    fun getLocalizedTerms(
+            userLanguage: String,
+            defaultLanguage: String = "en"
+    ): List<LocalizedFlowDataLoginTerms> {
         return policies?.map {
             val tos = policies[it.key] as? Map<*, *> ?: return@map null
             ((tos[userLanguage] ?: tos[defaultLanguage]) as? Map<*, *>)?.let { termsMap ->
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt
index 6c357b2224d04a7a511c963773cacea9323d2931..1ddce763d11faeedbab0a2399f81a28811b713c8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt
@@ -24,10 +24,12 @@ interface TermsService {
 
     suspend fun getTerms(serviceType: ServiceType, baseUrl: String): GetTermsResponse
 
-    suspend fun agreeToTerms(serviceType: ServiceType,
-                             baseUrl: String,
-                             agreedUrls: List<String>,
-                             token: String?)
+    suspend fun agreeToTerms(
+            serviceType: ServiceType,
+            baseUrl: String,
+            agreedUrls: List<String>,
+            token: String?
+    )
 
     /**
      * Get the homeserver terms, from the register API.
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 c110802d23a77d4463efe2fd459da3e81c196e1a..6825f8c27962da065f9ab687acc65b0752d0cc10 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
@@ -20,14 +20,19 @@ package org.matrix.android.sdk.api.session.threads
  * This class defines the state of a thread notification.
  */
 enum class ThreadNotificationState {
-
-    // There are no new message
+    /**
+     * There are no new message.
+     */
     NO_NEW_MESSAGE,
 
-    // There is at least one new message
+    /**
+     * There is at least one new message.
+     */
     NEW_MESSAGE,
 
-    // The is at least one new message that should be highlighted
-    // ex. "Hello @aris.kotsomitopoulos"
+    /**
+     * The is at least one new message that should be highlighted.
+     * ex. "Hello @aris.kotsomitopoulos"
+     */
     NEW_HIGHLIGHTED_MESSAGE;
 }
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 edb49f4797f2ac9f6a1cb6862de12052ad03be20..0c224ff17c668c185bb0a26b354485259ee33fb9 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
@@ -49,7 +49,7 @@ interface WidgetPostAPIMediator {
     /**
      * Send a boolean response.
      *
-     * @param response  the response
+     * @param response the response
      * @param eventData the modular data
      */
     fun sendBoolResponse(response: Boolean, eventData: JsonDict)
@@ -57,7 +57,7 @@ interface WidgetPostAPIMediator {
     /**
      * Send an integer response.
      *
-     * @param response  the response
+     * @param response the response
      * @param eventData the modular data
      */
     fun sendIntegerResponse(response: Int, eventData: JsonDict)
@@ -65,8 +65,9 @@ interface WidgetPostAPIMediator {
     /**
      * Send an object response.
      *
-     * @param klass the class of the response
-     * @param response  the response
+     * @param T the generic type
+     * @param type the type of the response
+     * @param response the response
      * @param eventData the modular data
      */
     fun <T> sendObjectResponse(type: Type, response: T?, eventData: JsonDict)
@@ -81,7 +82,7 @@ interface WidgetPostAPIMediator {
     /**
      * Send an error.
      *
-     * @param message   the error message
+     * @param message the error message
      * @param eventData the modular data
      */
     fun sendError(message: String, eventData: JsonDict)
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 b06f8f7bc6c682d5d1ec3a297d7ab2c4b0a2ffd5..8ad6500d25bb6c7b366309a3151aa1fed2855dc4 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
@@ -111,8 +111,8 @@ interface WidgetService {
     /**
      * Deactivate a widget in a room. It makes sure you have the rights to handle this.
      *
-     * @param roomId: the room where you want to deactivate the widget.
-     * @param widgetId: the widget to deactivate.
+     * @param roomId the room where you want to deactivate the widget.
+     * @param widgetId the widget to deactivate.
      */
     suspend fun destroyRoomWidget(roomId: String, widgetId: String)
 
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 8a29d003805072d445cee22c9249efbf6b2d97eb..26dd31dc2d4f214a12bbd9ef40121abfff635dee 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
@@ -33,9 +33,11 @@ sealed class MatrixItem(
         open val displayName: String?,
         open val avatarUrl: String?
 ) {
-    data class UserItem(override val id: String,
-                        override val displayName: String? = null,
-                        override val avatarUrl: String? = null) :
+    data class UserItem(
+            override val id: String,
+            override val displayName: String? = null,
+            override val avatarUrl: String? = null
+    ) :
             MatrixItem(id, displayName?.removeSuffix(IRC_PATTERN), avatarUrl) {
 
         init {
@@ -45,10 +47,12 @@ sealed class MatrixItem(
         override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
     }
 
-    data class EveryoneInRoomItem(override val id: String,
-                                  override val displayName: String = NOTIFY_EVERYONE,
-                                  override val avatarUrl: String? = null,
-                                  val roomDisplayName: String? = null) :
+    data class EveryoneInRoomItem(
+            override val id: String,
+            override val displayName: String = NOTIFY_EVERYONE,
+            override val avatarUrl: String? = null,
+            val roomDisplayName: String? = null
+    ) :
             MatrixItem(id, displayName, avatarUrl) {
         init {
             if (BuildConfig.DEBUG) checkId()
@@ -57,9 +61,11 @@ sealed class MatrixItem(
         override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
     }
 
-    data class EventItem(override val id: String,
-                         override val displayName: String? = null,
-                         override val avatarUrl: String? = null) :
+    data class EventItem(
+            override val id: String,
+            override val displayName: String? = null,
+            override val avatarUrl: String? = null
+    ) :
             MatrixItem(id, displayName, avatarUrl) {
         init {
             if (BuildConfig.DEBUG) checkId()
@@ -68,9 +74,11 @@ sealed class MatrixItem(
         override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
     }
 
-    data class RoomItem(override val id: String,
-                        override val displayName: String? = null,
-                        override val avatarUrl: String? = null) :
+    data class RoomItem(
+            override val id: String,
+            override val displayName: String? = null,
+            override val avatarUrl: String? = null
+    ) :
             MatrixItem(id, displayName, avatarUrl) {
         init {
             if (BuildConfig.DEBUG) checkId()
@@ -79,9 +87,11 @@ sealed class MatrixItem(
         override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
     }
 
-    data class SpaceItem(override val id: String,
-                         override val displayName: String? = null,
-                         override val avatarUrl: String? = null) :
+    data class SpaceItem(
+            override val id: String,
+            override val displayName: String? = null,
+            override val avatarUrl: String? = null
+    ) :
             MatrixItem(id, displayName, avatarUrl) {
         init {
             if (BuildConfig.DEBUG) checkId()
@@ -90,9 +100,11 @@ sealed class MatrixItem(
         override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
     }
 
-    data class RoomAliasItem(override val id: String,
-                             override val displayName: String? = null,
-                             override val avatarUrl: String? = null) :
+    data class RoomAliasItem(
+            override val id: String,
+            override val displayName: String? = null,
+            override val avatarUrl: String? = null
+    ) :
             MatrixItem(id, displayName, avatarUrl) {
         init {
             if (BuildConfig.DEBUG) checkId()
@@ -101,9 +113,11 @@ sealed class MatrixItem(
         override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
     }
 
-    data class GroupItem(override val id: String,
-                         override val displayName: String? = null,
-                         override val avatarUrl: String? = null) :
+    data class GroupItem(
+            override val id: String,
+            override val displayName: String? = null,
+            override val avatarUrl: String? = null
+    ) :
             MatrixItem(id, displayName, avatarUrl) {
         init {
             if (BuildConfig.DEBUG) checkId()
@@ -124,20 +138,20 @@ sealed class MatrixItem(
      * Return the prefix as defined in the matrix spec (and not extracted from the id).
      */
     private fun getIdPrefix() = when (this) {
-        is UserItem           -> '@'
-        is EventItem          -> '$'
+        is UserItem -> '@'
+        is EventItem -> '$'
         is SpaceItem,
         is RoomItem,
         is EveryoneInRoomItem -> '!'
-        is RoomAliasItem      -> '#'
-        is GroupItem          -> '+'
+        is RoomAliasItem -> '#'
+        is GroupItem -> '+'
     }
 
     fun firstLetterOfDisplayName(): String {
         val displayName = when (this) {
             // use the room display name for the notify everyone item
             is EveryoneInRoomItem -> roomDisplayName
-            else                  -> displayName
+            else -> displayName
         }
         return (displayName?.takeIf { it.isNotBlank() } ?: id)
                 .let { dn ->
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt
index 934d61de45f99dde9255e22cdeb9b470e159f4e6..bd2dac9e3ccaef4f3c31870a2f33942f4f9e01e3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt
@@ -27,8 +27,10 @@ import org.matrix.android.sdk.internal.session.SessionComponent
 import javax.inject.Inject
 
 @MatrixScope
-internal class SessionManager @Inject constructor(private val matrixComponent: MatrixComponent,
-                                                  private val sessionParamsStore: SessionParamsStore) {
+internal class SessionManager @Inject constructor(
+        private val matrixComponent: MatrixComponent,
+        private val sessionParamsStore: SessionParamsStore
+) {
 
     // SessionId -> SessionComponent
     private val sessionComponents = HashMap<String, SessionComponent>()
@@ -53,7 +55,7 @@ internal class SessionManager @Inject constructor(private val matrixComponent: M
 
     fun stopSession(sessionId: String) {
         val sessionComponent = sessionComponents[sessionId] ?: throw RuntimeException("You don't have a session for id $sessionId")
-        sessionComponent.session().stopSync()
+        sessionComponent.session().syncService().stopSync()
     }
 
     fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent {
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 46fa63334cb9ed571eb94f33541de0045148cddf..ea4502824e2409f43c7ba3dbf28d567070db51d9 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
@@ -98,15 +98,19 @@ internal interface AuthAPI {
      * https://github.com/matrix-org/matrix-doc/pull/2290
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "register/{threePid}/requestToken")
-    suspend fun add3Pid(@Path("threePid") threePid: String,
-                        @Body params: AddThreePidRegistrationParams): AddThreePidRegistrationResponse
+    suspend fun add3Pid(
+            @Path("threePid") threePid: String,
+            @Body params: AddThreePidRegistrationParams
+    ): AddThreePidRegistrationResponse
 
     /**
      * Validate 3pid.
      */
     @POST
-    suspend fun validate3Pid(@Url url: String,
-                             @Body params: ValidationCodeBody): SuccessResult
+    suspend fun validate3Pid(
+            @Url url: String,
+            @Body params: ValidationCodeBody
+    ): SuccessResult
 
     /**
      * Get the supported login flow.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt
index 298e116199642fcedd68436976681ccd49f3327c..ddb70be906b15b8e84d872eab2ab9edc9fb6ef23 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt
@@ -46,9 +46,11 @@ internal abstract class AuthModule {
         @JvmStatic
         @Provides
         @AuthDatabase
-        fun providesRealmConfiguration(context: Context,
-                                       realmKeysUtils: RealmKeysUtils,
-                                       authRealmMigration: AuthRealmMigration): RealmConfiguration {
+        fun providesRealmConfiguration(
+                context: Context,
+                realmKeysUtils: RealmKeysUtils,
+                authRealmMigration: AuthRealmMigration
+        ): RealmConfiguration {
             val old = File(context.filesDir, "matrix-sdk-auth")
             if (old.exists()) {
                 old.renameTo(File(context.filesDir, "matrix-sdk-auth.realm"))
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 f1cfe3fee5ec6095122af7466c6edccbd9088592..61a423669c46ea9e43fae37217edadc743246712 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
@@ -20,7 +20,7 @@ import android.net.Uri
 import dagger.Lazy
 import okhttp3.OkHttpClient
 import org.matrix.android.sdk.api.MatrixPatterns
-import org.matrix.android.sdk.api.MatrixPatterns.getDomain
+import org.matrix.android.sdk.api.MatrixPatterns.getServerName
 import org.matrix.android.sdk.api.auth.AuthenticationService
 import org.matrix.android.sdk.api.auth.data.Credentials
 import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
@@ -130,16 +130,7 @@ internal class DefaultAuthenticationService @Inject constructor(
                 ?.trim { it == '/' }
     }
 
-    /**
-     * This is the entry point of the authentication service.
-     * homeServerConnectionConfig contains a homeserver URL probably entered by the user, which can be a
-     * valid homeserver API url, the url of Element Web, or anything else.
-     */
     override suspend fun getLoginFlow(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult {
-        pendingSessionData = null
-
-        pendingSessionStore.delete()
-
         val result = runCatching {
             getLoginFlowInternal(homeServerConnectionConfig)
         }
@@ -290,7 +281,7 @@ internal class DefaultAuthenticationService @Inject constructor(
 
                 getLoginFlowResult(newAuthAPI, versions, wellknownResult.homeServerUrl)
             }
-            else                      -> throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */)
+            else -> throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */)
         }
     }
 
@@ -323,8 +314,7 @@ internal class DefaultAuthenticationService @Inject constructor(
                 }
     }
 
-    override val isRegistrationStarted: Boolean
-        get() = currentRegistrationWizard?.isRegistrationStarted == true
+    override fun isRegistrationStarted() = currentRegistrationWizard?.isRegistrationStarted() == true
 
     override fun getLoginWizard(): LoginWizard {
         return currentLoginWizard
@@ -368,20 +358,24 @@ internal class DefaultAuthenticationService @Inject constructor(
         pendingSessionStore.delete()
     }
 
-    override suspend fun createSessionFromSso(homeServerConnectionConfig: HomeServerConnectionConfig,
-                                              credentials: Credentials): Session {
+    override suspend fun createSessionFromSso(
+            homeServerConnectionConfig: HomeServerConnectionConfig,
+            credentials: Credentials
+    ): Session {
         return sessionCreator.createSession(credentials, homeServerConnectionConfig)
     }
 
-    override suspend fun getWellKnownData(matrixId: String,
-                                          homeServerConnectionConfig: HomeServerConnectionConfig?): WellknownResult {
+    override suspend fun getWellKnownData(
+            matrixId: String,
+            homeServerConnectionConfig: HomeServerConnectionConfig?
+    ): WellknownResult {
         if (!MatrixPatterns.isUserId(matrixId)) {
             throw MatrixIdFailure.InvalidMatrixId
         }
 
         return getWellknownTask.execute(
                 GetWellknownTask.Params(
-                        domain = matrixId.getDomain(),
+                        domain = matrixId.getServerName().substringBeforeLast(":"),
                         homeServerConnectionConfig = homeServerConnectionConfig.orWellKnownDefaults()
                 )
         )
@@ -392,11 +386,13 @@ internal class DefaultAuthenticationService @Inject constructor(
             .withHomeServerUri("https://dummy.org")
             .build()
 
-    override suspend fun directAuthentication(homeServerConnectionConfig: HomeServerConnectionConfig,
-                                              matrixId: String,
-                                              password: String,
-                                              initialDeviceName: String,
-                                              deviceId: String?): Session {
+    override suspend fun directAuthentication(
+            homeServerConnectionConfig: HomeServerConnectionConfig,
+            matrixId: String,
+            password: String,
+            initialDeviceName: String,
+            deviceId: String?
+    ): Session {
         return directLoginTask.execute(
                 DirectLoginTask.Params(
                         homeServerConnectionConfig = homeServerConnectionConfig,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt
index 5be480f633b8096c8211f83051e7a34d9429d22e..5f0a2298cb670acad891450f0a6a68adbea4bca7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt
@@ -31,7 +31,8 @@ internal data class PasswordLoginParams(
         @Json(name = "password") val password: String,
         @Json(name = "type") override val type: String,
         @Json(name = "initial_device_display_name") val deviceDisplayName: String?,
-        @Json(name = "device_id") val deviceId: String?) : LoginParams {
+        @Json(name = "device_id") val deviceId: String?
+) : LoginParams {
 
     companion object {
         private const val IDENTIFIER_KEY_TYPE = "type"
@@ -47,10 +48,12 @@ internal data class PasswordLoginParams(
         private const val IDENTIFIER_KEY_COUNTRY = "country"
         private const val IDENTIFIER_KEY_PHONE = "phone"
 
-        fun userIdentifier(user: String,
-                           password: String,
-                           deviceDisplayName: String?,
-                           deviceId: String?): PasswordLoginParams {
+        fun userIdentifier(
+                user: String,
+                password: String,
+                deviceDisplayName: String?,
+                deviceId: String?
+        ): PasswordLoginParams {
             return PasswordLoginParams(
                     identifier = mapOf(
                             IDENTIFIER_KEY_TYPE to IDENTIFIER_KEY_TYPE_USER,
@@ -63,11 +66,13 @@ internal data class PasswordLoginParams(
             )
         }
 
-        fun thirdPartyIdentifier(medium: String,
-                                 address: String,
-                                 password: String,
-                                 deviceDisplayName: String?,
-                                 deviceId: String?): PasswordLoginParams {
+        fun thirdPartyIdentifier(
+                medium: String,
+                address: String,
+                password: String,
+                deviceDisplayName: String?,
+                deviceId: String?
+        ): PasswordLoginParams {
             return PasswordLoginParams(
                     identifier = mapOf(
                             IDENTIFIER_KEY_TYPE to IDENTIFIER_KEY_TYPE_THIRD_PARTY,
@@ -81,11 +86,13 @@ internal data class PasswordLoginParams(
             )
         }
 
-        fun phoneIdentifier(country: String,
-                            phone: String,
-                            password: String,
-                            deviceDisplayName: String?,
-                            deviceId: String?): PasswordLoginParams {
+        fun phoneIdentifier(
+                country: String,
+                phone: String,
+                password: String,
+                deviceDisplayName: String?,
+                deviceId: String?
+        ): PasswordLoginParams {
             return PasswordLoginParams(
                     identifier = mapOf(
                             IDENTIFIER_KEY_TYPE to IDENTIFIER_KEY_TYPE_PHONE,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmPendingSessionStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmPendingSessionStore.kt
index 13f26e321dad8c0abd52d863eabd50caa7ce4c87..aae8ff8419dd9bd3292b17637f1070e186b50f80 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmPendingSessionStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmPendingSessionStore.kt
@@ -23,9 +23,10 @@ import org.matrix.android.sdk.internal.database.awaitTransaction
 import org.matrix.android.sdk.internal.di.AuthDatabase
 import javax.inject.Inject
 
-internal class RealmPendingSessionStore @Inject constructor(private val mapper: PendingSessionMapper,
-                                                            @AuthDatabase
-                                                            private val realmConfiguration: RealmConfiguration
+internal class RealmPendingSessionStore @Inject constructor(
+        private val mapper: PendingSessionMapper,
+        @AuthDatabase
+        private val realmConfiguration: RealmConfiguration
 ) : PendingSessionStore {
 
     override suspend fun savePendingSessionData(pendingSessionData: PendingSessionData) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmSessionParamsStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmSessionParamsStore.kt
index 235ef6b7092ef39e6f6080f1329372cf804a12e5..4c3e3ca824d56f8cfa135215d4922875e4d8f43b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmSessionParamsStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmSessionParamsStore.kt
@@ -28,9 +28,10 @@ import org.matrix.android.sdk.internal.di.AuthDatabase
 import timber.log.Timber
 import javax.inject.Inject
 
-internal class RealmSessionParamsStore @Inject constructor(private val mapper: SessionParamsMapper,
-                                                           @AuthDatabase
-                                                           private val realmConfiguration: RealmConfiguration
+internal class RealmSessionParamsStore @Inject constructor(
+        private val mapper: SessionParamsMapper,
+        @AuthDatabase
+        private val realmConfiguration: RealmConfiguration
 ) : SessionParamsStore {
 
     override fun getLast(): SessionParams? {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt
index 058395113837ddc975a864c71d3aba04ae33b7d5..20b056f1c79bcd3300a09d281e89e8c7a122e5d2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt
@@ -52,10 +52,12 @@ internal class DefaultLoginWizard(
         return getProfileTask.execute(GetProfileTask.Params(matrixId))
     }
 
-    override suspend fun login(login: String,
-                               password: String,
-                               initialDeviceName: String,
-                               deviceId: String?): Session {
+    override suspend fun login(
+            login: String,
+            password: String,
+            initialDeviceName: String,
+            deviceId: String?
+    ): Session {
         val loginParams = if (Patterns.EMAIL_ADDRESS.matcher(login).matches()) {
             PasswordLoginParams.thirdPartyIdentifier(
                     medium = ThreePidMedium.EMAIL,
@@ -101,7 +103,7 @@ internal class DefaultLoginWizard(
         return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig)
     }
 
-    override suspend fun resetPassword(email: String, newPassword: String) {
+    override suspend fun resetPassword(email: String) {
         val param = RegisterAddThreePidTask.Params(
                 RegisterThreePid.Email(email),
                 pendingSessionData.clientSecret,
@@ -115,18 +117,16 @@ internal class DefaultLoginWizard(
             authAPI.resetPassword(AddThreePidRegistrationParams.from(param))
         }
 
-        pendingSessionData = pendingSessionData.copy(resetPasswordData = ResetPasswordData(newPassword, result))
+        pendingSessionData = pendingSessionData.copy(resetPasswordData = ResetPasswordData(result))
                 .also { pendingSessionStore.savePendingSessionData(it) }
     }
 
-    override suspend fun resetPasswordMailConfirmed() {
-        val safeResetPasswordData = pendingSessionData.resetPasswordData
-                ?: throw IllegalStateException("developer error, no reset password in progress")
-
+    override suspend fun resetPasswordMailConfirmed(newPassword: String) {
+        val resetPasswordData = pendingSessionData.resetPasswordData ?: throw IllegalStateException("Developer error - Must call resetPassword first")
         val param = ResetPasswordMailConfirmed.create(
                 pendingSessionData.clientSecret,
-                safeResetPasswordData.addThreePidRegistrationResponse.sid,
-                safeResetPasswordData.newPassword
+                resetPasswordData.addThreePidRegistrationResponse.sid,
+                newPassword
         )
 
         executeRequest(null) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt
index 28706c7e8081edab796743bbcd9fbf498680cd93..c9311867c8c6bffee491b9ae835fdc5a4b586cca 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt
@@ -73,7 +73,7 @@ internal class DefaultDirectLoginTask @Inject constructor(
                         homeServerUrl,
                         throwable.fingerprint
                 )
-                else                                -> throwable
+                else -> throwable
             }
         }
 
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 a65ec38d6d851be2bfa9444bc38c351fba1059f3..87a7b346dcf26ed33fe6dbf72661c93ba84dc78d 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
@@ -24,6 +24,5 @@ import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistration
  */
 @JsonClass(generateAdapter = true)
 internal data class ResetPasswordData(
-        val newPassword: String,
         val addThreePidRegistrationResponse: AddThreePidRegistrationResponse
 )
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 2f05864d3bfb0252da8de2a399accd47edf75a9d..f0cb6ebd6ddf656686e9e959c9c9efaca78b6e0a 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
@@ -84,7 +84,7 @@ internal data class AddThreePidRegistrationParams(
     companion object {
         fun from(params: RegisterAddThreePidTask.Params): AddThreePidRegistrationParams {
             return when (params.threePid) {
-                is RegisterThreePid.Email  -> AddThreePidRegistrationParams(
+                is RegisterThreePid.Email -> AddThreePidRegistrationParams(
                         email = params.threePid.email,
                         clientSecret = params.clientSecret,
                         sendAttempt = params.sendAttempt
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 8f00f3440c02e2129ad1a0a378b6d5a0f3d7818c..d6ec0297b4a88e900805f0ec15e7c0c8466305a3 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
@@ -49,29 +49,29 @@ internal class DefaultRegistrationWizard(
     private val validateCodeTask: ValidateCodeTask = DefaultValidateCodeTask(authAPI)
     private val registerCustomTask: RegisterCustomTask = DefaultRegisterCustomTask(authAPI)
 
-    override val currentThreePid: String?
-        get() {
-            return when (val threePid = pendingSessionData.currentThreePidData?.threePid) {
-                is RegisterThreePid.Email  -> threePid.email
-                is RegisterThreePid.Msisdn -> {
-                    // Take formatted msisdn if provided by the server
-                    pendingSessionData.currentThreePidData?.addThreePidRegistrationResponse?.formattedMsisdn?.takeIf { it.isNotBlank() } ?: threePid.msisdn
-                }
-                null                       -> null
+    override fun getCurrentThreePid(): String? {
+        return when (val threePid = pendingSessionData.currentThreePidData?.threePid) {
+            is RegisterThreePid.Email -> threePid.email
+            is RegisterThreePid.Msisdn -> {
+                // Take formatted msisdn if provided by the server
+                pendingSessionData.currentThreePidData?.addThreePidRegistrationResponse?.formattedMsisdn?.takeIf { it.isNotBlank() } ?: threePid.msisdn
             }
+            null -> null
         }
+    }
 
-    override val isRegistrationStarted: Boolean
-        get() = pendingSessionData.isRegistrationStarted
+    override fun isRegistrationStarted() = pendingSessionData.isRegistrationStarted
 
     override suspend fun getRegistrationFlow(): RegistrationResult {
         val params = RegistrationParams()
         return performRegistrationRequest(params)
     }
 
-    override suspend fun createAccount(userName: String?,
-                                       password: String?,
-                                       initialDeviceDisplayName: String?): RegistrationResult {
+    override suspend fun createAccount(
+            userName: String?,
+            password: String?,
+            initialDeviceDisplayName: String?
+    ): RegistrationResult {
         val params = RegistrationParams(
                 username = userName,
                 password = password,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegisterAddThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegisterAddThreePidTask.kt
index 54a8ba0e6ce94786fd7e61f9cae3ee9da1c1ed20..b84ed613615a0399200f1e53fd6584362dae7474 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegisterAddThreePidTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegisterAddThreePidTask.kt
@@ -41,7 +41,7 @@ internal class DefaultRegisterAddThreePidTask(
 
     private fun RegisterThreePid.toPath(): String {
         return when (this) {
-            is RegisterThreePid.Email  -> "email"
+            is RegisterThreePid.Email -> "email"
             is RegisterThreePid.Msisdn -> "msisdn"
         }
     }
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 c8f71af3065192a56a5812e80d15d2ed49213b35..dde0a44ea06d6a19adbb34800448ee477a30d191 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
@@ -40,11 +40,13 @@ internal data class ThreePidData(
         }
 
     companion object {
-        fun from(threePid: RegisterThreePid,
-                 addThreePidRegistrationResponse: AddThreePidRegistrationResponse,
-                 registrationParams: RegistrationParams): ThreePidData {
+        fun from(
+                threePid: RegisterThreePid,
+                addThreePidRegistrationResponse: AddThreePidRegistrationResponse,
+                registrationParams: RegistrationParams
+        ): ThreePidData {
             return when (threePid) {
-                is RegisterThreePid.Email  ->
+                is RegisterThreePid.Email ->
                     ThreePidData(threePid.email, "", "", addThreePidRegistrationResponse, registrationParams)
                 is RegisterThreePid.Msisdn ->
                     ThreePidData("", threePid.msisdn, threePid.countryCode, addThreePidRegistrationResponse, registrationParams)
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 9b135c347d427728cd46d0f2fee3983cd93df6d8..8118f9faff3161d6a4196c3adf05c3b35c0f2a0c 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
@@ -35,9 +35,11 @@ import kotlin.coroutines.suspendCoroutine
  * @return UiaResult if UIA handled, failed or cancelled
  *
  */
-internal suspend fun handleUIA(failure: Throwable,
-                               interceptor: UserInteractiveAuthInterceptor,
-                               retryBlock: suspend (UIABaseAuth) -> Unit): UiaResult {
+internal suspend fun handleUIA(
+        failure: Throwable,
+        interceptor: UserInteractiveAuthInterceptor,
+        retryBlock: suspend (UIABaseAuth) -> Unit
+): UiaResult {
     Timber.d("## UIA: check error ${failure.message}")
     val flowResponse = failure.toRegistrationFlowResponse()
             ?: return UiaResult.FAILURE.also {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt
index 815f8de2de28b80c6a1067f943b2e67b3e21395c..cd38b68a85ec10a9b4101fc9c44061c6d2b80674 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt
@@ -16,6 +16,8 @@
 
 package org.matrix.android.sdk.internal.auth.version
 
+import org.matrix.android.sdk.api.extensions.ensureNotEmpty
+
 /**
  * Values will take the form "rX.Y.Z".
  * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-versions
@@ -33,19 +35,19 @@ internal data class HomeServerVersion(
             minor < other.minor -> -1
             patch > other.patch -> 1
             patch < other.patch -> -1
-            else                -> 0
+            else -> 0
         }
     }
 
     companion object {
-        internal val pattern = Regex("""[r|v](\d+)\.(\d+)\.(\d+)""")
+        internal val pattern = Regex("""[r|v](\d+)\.(\d+)(?:\.(\d+))?""")
 
         internal fun parse(value: String): HomeServerVersion? {
             val result = pattern.matchEntire(value) ?: return null
             return HomeServerVersion(
                     major = result.groupValues[1].toInt(),
                     minor = result.groupValues[2].toInt(),
-                    patch = result.groupValues[3].toInt()
+                    patch = result.groupValues.getOrNull(index = 3)?.ensureNotEmpty()?.toInt() ?: 0
             )
         }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt
index 2265526484bd5b734ea2cedeb5c111c953b3b3cc..c69a8590168db42769ceb713adb9087d09681e58 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt
@@ -110,10 +110,12 @@ internal abstract class CryptoModule {
         @Provides
         @CryptoDatabase
         @SessionScope
-        fun providesRealmConfiguration(@SessionFilesDirectory directory: File,
-                                       @UserMd5 userMd5: String,
-                                       realmKeysUtils: RealmKeysUtils,
-                                       realmCryptoStoreMigration: RealmCryptoStoreMigration): RealmConfiguration {
+        fun providesRealmConfiguration(
+                @SessionFilesDirectory directory: File,
+                @UserMd5 userMd5: String,
+                realmKeysUtils: RealmKeysUtils,
+                realmCryptoStoreMigration: RealmCryptoStoreMigration
+        ): RealmConfiguration {
             return RealmConfiguration.Builder()
                     .directory(directory)
                     .apply {
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 b3e9eab9880b1f0fa8ec3d372940273abc42530b..eee1ee70aa91f1399388f69494c3e43df84adb38 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
@@ -46,6 +46,7 @@ internal class CryptoSessionInfoProvider @Inject constructor(
     }
 
     /**
+     * @param roomId the room Id
      * @param allActive if true return joined as well as invited, if false, only joined
      */
     fun getRoomUserIds(roomId: String, allActive: Boolean): List<String> {
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 11fa93dbe05753ac457afa7298de581415329123..719f366518fd685e41ebe0f75dda37bdd3321e9d 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
@@ -188,8 +188,8 @@ internal class DefaultCryptoService @Inject constructor(
 
     fun onStateEvent(roomId: String, event: Event) {
         when (event.type) {
-            EventType.STATE_ROOM_ENCRYPTION         -> onRoomEncryptionEvent(roomId, event)
-            EventType.STATE_ROOM_MEMBER             -> onRoomMembershipEvent(roomId, event)
+            EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
+            EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
             EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
         }
     }
@@ -198,8 +198,8 @@ internal class DefaultCryptoService @Inject constructor(
         // handle state events
         if (event.isStateEvent()) {
             when (event.type) {
-                EventType.STATE_ROOM_ENCRYPTION         -> onRoomEncryptionEvent(roomId, event)
-                EventType.STATE_ROOM_MEMBER             -> onRoomMembershipEvent(roomId, event)
+                EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
+                EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
                 EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
             }
         }
@@ -508,7 +508,7 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * Provides the device information for a user id and a device Id.
      *
-     * @param userId   the user id
+     * @param userId the user id
      * @param deviceId the device id
      */
     override fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? {
@@ -538,7 +538,7 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * 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 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
      */
     override fun setDevicesKnown(devices: List<MXDeviceInfo>, callback: MatrixCallback<Unit>?) {
@@ -576,8 +576,8 @@ internal class DefaultCryptoService @Inject constructor(
      * Update the blocked/verified state of the given device.
      *
      * @param trustLevel the new trust level
-     * @param userId     the owner of the device
-     * @param deviceId   the unique identifier for the device.
+     * @param userId the owner of the device
+     * @param deviceId the unique identifier for the device.
      */
     override fun setDeviceVerification(trustLevel: DeviceTrustLevel, userId: String, deviceId: String) {
         setDeviceVerificationAction.handle(trustLevel, userId, deviceId)
@@ -586,16 +586,18 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * Configure a room to use encryption.
      *
-     * @param roomId             the room id to enable encryption in.
-     * @param algorithm          the encryption config for the room.
+     * @param roomId the room id to enable encryption in.
+     * @param algorithm the encryption config for the room.
      * @param inhibitDeviceQuery true to suppress device list query for users in the room (for now)
-     * @param membersId          list of members to start tracking their devices
+     * @param membersId list of members to start tracking their devices
      * @return true if the operation succeeds.
      */
-    private suspend fun setEncryptionInRoom(roomId: String,
-                                            algorithm: String?,
-                                            inhibitDeviceQuery: Boolean,
-                                            membersId: List<String>): Boolean {
+    private suspend fun setEncryptionInRoom(
+            roomId: String,
+            algorithm: String?,
+            inhibitDeviceQuery: Boolean,
+            membersId: List<String>
+    ): Boolean {
         // If we already have encryption in this room, we should ignore this event
         // (for now at least. Maybe we should alert the user somehow?)
         val existingAlgorithm = cryptoStore.getRoomAlgorithm(roomId)
@@ -618,8 +620,8 @@ internal class DefaultCryptoService @Inject constructor(
 
         val alg: IMXEncrypting? = when (algorithm) {
             MXCRYPTO_ALGORITHM_MEGOLM -> megolmEncryptionFactory.create(roomId)
-            MXCRYPTO_ALGORITHM_OLM    -> olmEncryptionFactory.create(roomId)
-            else                      -> null
+            MXCRYPTO_ALGORITHM_OLM -> olmEncryptionFactory.create(roomId)
+            else -> null
         }
 
         if (alg != null) {
@@ -687,14 +689,16 @@ internal class DefaultCryptoService @Inject constructor(
      * Encrypt an event content according to the configuration of the room.
      *
      * @param eventContent the content of the event.
-     * @param eventType    the type of the event.
-     * @param roomId       the room identifier the event will be sent.
-     * @param callback     the asynchronous callback
+     * @param eventType the type of the event.
+     * @param roomId the room identifier the event will be sent.
+     * @param callback the asynchronous callback
      */
-    override fun encryptEventContent(eventContent: Content,
-                                     eventType: String,
-                                     roomId: String,
-                                     callback: MatrixCallback<MXEncryptEventContentResult>) {
+    override fun encryptEventContent(
+            eventContent: Content,
+            eventType: String,
+            roomId: String,
+            callback: MatrixCallback<MXEncryptEventContentResult>
+    ) {
         // moved to crypto scope to have uptodate values
         cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
             val userIds = getRoomUserIds(roomId)
@@ -742,7 +746,7 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * Decrypt an event.
      *
-     * @param event    the raw 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.
      * @return the MXEventDecryptionResult data, or throw in case of error
      */
@@ -754,7 +758,7 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * Decrypt an event asynchronously.
      *
-     * @param event    the raw 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.
      * @param callback the callback to return data or null
      */
@@ -765,7 +769,7 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * Decrypt an event.
      *
-     * @param event    the raw 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.
      * @return the MXEventDecryptionResult data, or null in case of error
      */
@@ -796,10 +800,10 @@ internal class DefaultCryptoService @Inject constructor(
                     // 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                       -> {
+                EventType.ROOM_KEY_REQUEST -> {
                     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,
@@ -811,13 +815,13 @@ internal class DefaultCryptoService @Inject constructor(
                         }
                     }
                 }
-                EventType.SEND_SECRET                            -> {
+                EventType.SEND_SECRET -> {
                     onSecretSendReceived(event)
                 }
-                EventType.ROOM_KEY_WITHHELD                      -> {
+                EventType.ROOM_KEY_WITHHELD -> {
                     onKeyWithHeldReceived(event)
                 }
-                else                                             -> {
+                else -> {
                     // ignore
                 }
             }
@@ -879,10 +883,12 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * 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       -> {
+            MASTER_KEY_SSSS_NAME -> {
                 crossSigningService.onSecretMSKGossip(secretValue)
                 true
             }
@@ -898,13 +904,14 @@ internal class DefaultCryptoService @Inject constructor(
                 keysBackupService.onSecretKeyGossip(secretValue)
                 true
             }
-            else                       -> false
+            else -> false
         }
     }
 
     /**
      * Handle an m.room.encryption event.
      *
+     * @param roomId the room Id
      * @param event the encryption event.
      */
     private fun onRoomEncryptionEvent(roomId: String, event: Event) {
@@ -928,6 +935,7 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * Handle a change in the membership state of a member of a room.
      *
+     * @param roomId the room Id
      * @param event the membership event causing the change
      */
     private fun onRoomMembershipEvent(roomId: String, event: Event) {
@@ -996,7 +1004,7 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * Export the crypto keys.
      *
-     * @param password         the password
+     * @param password the password
      * @param anIterationCount the encryption iteration count (0 means no encryption)
      */
     private suspend fun exportRoomKeys(password: String, anIterationCount: Int): ByteArray {
@@ -1015,14 +1023,16 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * Import the room keys.
      *
-     * @param roomKeysAsArray  the room keys as array.
-     * @param password         the password
+     * @param roomKeysAsArray the room keys as array.
+     * @param password the password
      * @param progressListener the progress listener
      * @return the result ImportRoomKeysResult
      */
-    override suspend fun importRoomKeys(roomKeysAsArray: ByteArray,
-                                        password: String,
-                                        progressListener: ProgressListener?): ImportRoomKeysResult {
+    override suspend fun importRoomKeys(
+            roomKeysAsArray: ByteArray,
+            password: String,
+            progressListener: ProgressListener?
+    ): ImportRoomKeysResult {
         return withContext(coroutineDispatchers.crypto) {
             Timber.tag(loggerTag.value).v("importRoomKeys starts")
 
@@ -1066,7 +1076,7 @@ internal class DefaultCryptoService @Inject constructor(
      * A success means there is no unknown devices.
      * If there are some unknown devices, a MXCryptoError.UnknownDevice exception is triggered.
      *
-     * @param userIds  the user ids list
+     * @param userIds the user ids list
      * @param callback the asynchronous callback.
      */
     fun checkUnknownDevices(userIds: List<String>, callback: MatrixCallback<Unit>) {
@@ -1089,7 +1099,7 @@ internal class DefaultCryptoService @Inject constructor(
      * If false, it can still be overridden per-room.
      * If true, it overrides the per-room settings.
      *
-     * @param block    true to unilaterally blacklist all
+     * @param block true to unilaterally blacklist all
      */
     override fun setGlobalBlacklistUnverifiedDevices(block: Boolean) {
         cryptoStore.setGlobalBlacklistUnverifiedDevices(block)
@@ -1129,8 +1139,8 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * Manages the room black-listing for unverified devices.
      *
-     * @param roomId   the room id
-     * @param add      true to add the room id to the list, false to remove it.
+     * @param roomId the room id
+     * @param add true to add the room id to the list, false to remove it.
      */
     private fun setRoomBlacklistUnverifiedDevices(roomId: String, add: Boolean) {
         val roomIds = cryptoStore.getRoomsListBlacklistUnverifiedDevices().toMutableList()
@@ -1149,7 +1159,7 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * Add this room to the ones which don't encrypt messages to unverified devices.
      *
-     * @param roomId   the room id
+     * @param roomId the room id
      */
     override fun setRoomBlacklistUnverifiedDevices(roomId: String) {
         setRoomBlacklistUnverifiedDevices(roomId, true)
@@ -1158,7 +1168,7 @@ internal class DefaultCryptoService @Inject constructor(
     /**
      * Remove this room to the ones which don't encrypt messages to unverified devices.
      *
-     * @param roomId   the room id
+     * @param roomId the room id
      */
     override fun setRoomUnBlacklistUnverifiedDevices(roomId: String) {
         setRoomBlacklistUnverifiedDevices(roomId, false)
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 cd4e2a6d527663b4dd2a572ab20ce1cea4b969d1..4f3900adb95a9e95e1e78f7becb26b662f665e09 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
@@ -170,7 +170,7 @@ internal class DeviceListManager @Inject constructor(
      * 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
+     * @param left the user ids list which left a room
      */
     fun handleDeviceListsChanges(changed: Collection<String>, left: Collection<String>) {
         Timber.v("## CRYPTO: handleDeviceListsChanges changed: ${changed.logLimit()} / left: ${left.logLimit()}")
@@ -223,7 +223,7 @@ internal class DeviceListManager @Inject constructor(
     /**
      * The keys download succeeded.
      *
-     * @param userIds  the userIds list
+     * @param userIds the userIds list
      * @param failures the failure map.
      */
     private fun onKeysDownloadSucceed(userIds: List<String>, failures: Map<String, Map<String, Any>>?): MXUsersDevicesMap<CryptoDeviceInfo> {
@@ -231,8 +231,8 @@ internal class DeviceListManager @Inject constructor(
             for ((k, value) in failures) {
                 val statusCode = when (val status = value["status"]) {
                     is Double -> status.toInt()
-                    is Int    -> status.toInt()
-                    else      -> 0
+                    is Int -> status.toInt()
+                    else -> 0
                 }
                 if (statusCode == 503) {
                     synchronized(notReadyToRetryHS) {
@@ -276,7 +276,7 @@ internal class DeviceListManager @Inject constructor(
      * Download the device keys for a list of users and stores the keys in the MXStore.
      * It must be called in getEncryptingThreadHandler() thread.
      *
-     * @param userIds       The users to fetch.
+     * @param userIds The users to fetch.
      * @param forceDownload Always download the keys even if cached.
      */
     suspend fun downloadKeys(userIds: List<String>?, forceDownload: Boolean): MXUsersDevicesMap<CryptoDeviceInfo> {
@@ -421,9 +421,9 @@ internal class DeviceListManager @Inject constructor(
      * Validate device keys.
      * This method must called on getEncryptingThreadHandler() thread.
      *
-     * @param deviceKeys                 the device keys to validate.
-     * @param userId                     the id of the user of the device.
-     * @param deviceId                   the id of the device.
+     * @param deviceKeys the device keys to validate.
+     * @param userId the id of the user of the device.
+     * @param deviceId the id of the device.
      * @param previouslyStoredDeviceKeys the device keys we received before for this device
      * @return true if succeeds
      */
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 d6f881211c8c3f8848f6d1c840ff9503d90038da..c1d04eb22ba482fe4c7a8791233ef7730d478ad3 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
@@ -29,6 +29,7 @@ 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.OlmEventContent
+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.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
 import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
@@ -42,7 +43,7 @@ import javax.inject.Inject
 
 private const val SEND_TO_DEVICE_RETRY_COUNT = 3
 
-private val loggerTag = LoggerTag("CryptoSyncHandler", LoggerTag.CRYPTO)
+private val loggerTag = LoggerTag("EventDecryptor", LoggerTag.CRYPTO)
 
 @SessionScope
 internal class EventDecryptor @Inject constructor(
@@ -72,7 +73,7 @@ internal class EventDecryptor @Inject constructor(
     /**
      * Decrypt an event.
      *
-     * @param event    the raw 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.
      * @return the MXEventDecryptionResult data, or throw in case of error
      */
@@ -84,7 +85,7 @@ internal class EventDecryptor @Inject constructor(
     /**
      * Decrypt an event asynchronously.
      *
-     * @param event    the raw 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.
      * @param callback the callback to return data or null
      */
@@ -100,7 +101,7 @@ internal class EventDecryptor @Inject constructor(
     /**
      * Decrypt an event.
      *
-     * @param event    the raw 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.
      * @return the MXEventDecryptionResult data, or null in case of error
      */
@@ -110,6 +111,16 @@ internal class EventDecryptor @Inject constructor(
         if (eventContent == null) {
             Timber.tag(loggerTag.value).e("decryptEvent : empty event content")
             throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON)
+        } else if (event.isRedacted()) {
+            // we shouldn't attempt to decrypt a redacted event because the content is cleared and decryption will fail because of null algorithm
+            return MXEventDecryptionResult(
+                    clearEvent = mapOf(
+                            "room_id" to event.roomId.orEmpty(),
+                            "type" to EventType.MESSAGE,
+                            "content" to emptyMap<String, Any>(),
+                            "unsigned" to event.unsignedData.toContent()
+                    )
+            )
         } else {
             val algorithm = eventContent["algorithm"]?.toString()
             val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, algorithm)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt
index 28ddf291b216d987e785373a4a45eebad1ddf767..e4d322cadd3a148c840f33235b4ae905de57c0ae 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt
@@ -44,7 +44,8 @@ private val loggerTag = LoggerTag("InboundGroupSessionStore", LoggerTag.CRYPTO)
 internal class InboundGroupSessionStore @Inject constructor(
         private val store: IMXCryptoStore,
         private val cryptoCoroutineScope: CoroutineScope,
-        private val coroutineDispatchers: MatrixCoroutineDispatchers) {
+        private val coroutineDispatchers: MatrixCoroutineDispatchers
+) {
 
     private data class CacheKey(
             val sessionId: String,
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
index 13f2fb861abca650f8d9616b2b3592429293bbfa..7f36224daec5f66fef7c29588b130428ac5b1f7d 100644
--- 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
@@ -135,7 +135,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
                             // just add to the buffer
                             incomingRequestBuffer.add(validMegolmRequest)
                         }
-                        MegolmRequestAction.Cancel  -> {
+                        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 ->
@@ -159,7 +159,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
                         MegolmRequestAction.Request -> {
                             // it's already in buffer, nop keep existing
                         }
-                        MegolmRequestAction.Cancel  -> {
+                        MegolmRequestAction.Cancel -> {
                             // discard the request in buffer
                             incomingRequestBuffer.remove(existing)
                             outgoingRequestScope.launch(coroutineDispatchers.computation) {
@@ -369,9 +369,11 @@ internal class IncomingKeyRequestManager @Inject constructor(
         shareMegolmKey(validReq, requestingDevice, null)
     }
 
-    private suspend fun shareMegolmKey(validRequest: ValidMegolmRequestBody,
-                                       requestingDevice: CryptoDeviceInfo,
-                                       chainIndex: Long?): Boolean {
+    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()}")
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXCryptoAlgorithms.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXCryptoAlgorithms.kt
index 5a5ee9e6968cffaf6dae8bf8569a6b2cd59891f9..14b0e8e125588cd10cee0f3600125e92b190bfd8 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXCryptoAlgorithms.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXCryptoAlgorithms.kt
@@ -32,7 +32,7 @@ internal object MXCryptoAlgorithms {
         return when (algorithm) {
             MXCRYPTO_ALGORITHM_MEGOLM,
             MXCRYPTO_ALGORITHM_OLM -> true
-            else                   -> false
+            else -> false
         }
     }
 
@@ -47,7 +47,7 @@ internal object MXCryptoAlgorithms {
         return when (algorithm) {
             MXCRYPTO_ALGORITHM_MEGOLM,
             MXCRYPTO_ALGORITHM_OLM -> true
-            else                   -> false
+            else -> false
         }
     }
 
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 e4a0f0376e04079a4cbc64c95972981b3f11c87a..e0d6c25d70173b12875bd107c42e772ef0ae2ef1 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
@@ -68,7 +68,7 @@ internal object MXMegolmExportEncryption {
     /**
      * Decrypt a megolm key file.
      *
-     * @param data     the data to decrypt
+     * @param data the data to decrypt
      * @param password the password.
      * @return the decrypted output.
      * @throws Exception the failure reason
@@ -138,9 +138,9 @@ internal object MXMegolmExportEncryption {
     /**
      * Encrypt a string into the megolm export format.
      *
-     * @param data       the data to encrypt.
-     * @param password   the password
-     * @param kdf_rounds the iteration count
+     * @param data the data to encrypt.
+     * @param password the password
+     * @param kdfRounds the iteration count
      * @return the encrypted data
      * @throws Exception the failure reason
      */
@@ -304,9 +304,9 @@ internal object MXMegolmExportEncryption {
     /**
      * Derive the AES and HMAC-SHA-256 keys for the file.
      *
-     * @param salt       salt for pbkdf
+     * @param salt salt for pbkdf
      * @param iterations number of pbkdf iterations
-     * @param password   password
+     * @param password password
      * @return the derived keys
      */
     @Throws(Exception::class)
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 5620cbf7693dab07ec101ae72b0869b2bf4ff306..24b6fd166f316866affb67f718b8e68bd1bf37c7 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
@@ -96,8 +96,9 @@ internal class MXOlmDevice @Inject constructor(
     // So, store these message indexes per timeline id.
     //
     // The first level keys are timeline ids.
-    // The second level keys are strings of form "<senderKey>|<session_id>|<message_index>"
-    private val inboundGroupSessionMessageIndexes: MutableMap<String, MutableSet<String>> = HashMap()
+    // The second level values is a Map that represents:
+    // "<senderKey>|<session_id>|<roomId>|<message_index>" --> eventId
+    private val inboundGroupSessionMessageIndexes: MutableMap<String, MutableMap<String, String>> = HashMap()
 
     init {
         // Retrieve the account from the store
@@ -260,7 +261,7 @@ internal class MXOlmDevice @Inject constructor(
      * The new session will be stored in the MXStore.
      *
      * @param theirIdentityKey the remote user's Curve25519 identity key
-     * @param theirOneTimeKey  the remote user's one-time Curve25519 key
+     * @param theirOneTimeKey the remote user's one-time Curve25519 key
      * @return the session id for the outbound session.
      */
     fun createOutboundSession(theirIdentityKey: String, theirOneTimeKey: String): String? {
@@ -299,8 +300,8 @@ internal class MXOlmDevice @Inject constructor(
      * Generate a new inbound session, given an incoming message.
      *
      * @param theirDeviceIdentityKey the remote user's Curve25519 identity key.
-     * @param messageType            the message_type field from the received message (must be 0).
-     * @param ciphertext             base64-encoded body from the received message.
+     * @param messageType the message_type field from the received message (must be 0).
+     * @param ciphertext base64-encoded body from the received message.
      * @return {{payload: string, session_id: string}} decrypted payload, and session id of new session.
      */
     fun createInboundSession(theirDeviceIdentityKey: String, messageType: Int, ciphertext: String): Map<String, String>? {
@@ -394,8 +395,8 @@ internal class MXOlmDevice @Inject constructor(
      * Encrypt an outgoing message using an existing session.
      *
      * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device.
-     * @param sessionId              the id of the active session
-     * @param payloadString          the payload to be encrypted and sent
+     * @param sessionId the id of the active session
+     * @param payloadString the payload to be encrypted and sent
      * @return the cipher text
      */
     suspend fun encryptMessage(theirDeviceIdentityKey: String, sessionId: String, payloadString: String): Map<String, Any>? {
@@ -427,10 +428,10 @@ internal class MXOlmDevice @Inject constructor(
     /**
      * Decrypt an incoming message using an existing session.
      *
-     * @param ciphertext             the base64-encoded body from the received message.
-     * @param messageType            message_type field from the received message.
+     * @param ciphertext the base64-encoded body from the received message.
+     * @param messageType message_type field from the received message.
+     * @param sessionId the id of the active session.
      * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device.
-     * @param sessionId              the id of the active session.
      * @return the decrypted payload.
      */
     @kotlin.jvm.Throws
@@ -460,9 +461,9 @@ internal class MXOlmDevice @Inject constructor(
      * Determine if an incoming messages is a prekey message matching an existing session.
      *
      * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device.
-     * @param sessionId              the id of the active session.
-     * @param messageType            message_type field from the received message.
-     * @param ciphertext             the base64-encoded body from the received message.
+     * @param sessionId the id of the active session.
+     * @param messageType message_type field from the received message.
+     * @param ciphertext the base64-encoded body from the received message.
      * @return YES if the received message is a prekey message which matchesthe given session.
      */
     fun matchesSession(theirDeviceIdentityKey: String, sessionId: String, messageType: Int, ciphertext: String): Boolean {
@@ -563,7 +564,7 @@ internal class MXOlmDevice @Inject constructor(
     /**
      * Encrypt an outgoing message with an outbound group session.
      *
-     * @param sessionId     the id of the outbound group session.
+     * @param sessionId the id of the outbound group session.
      * @param payloadString the payload to be encrypted and sent.
      * @return ciphertext
      */
@@ -590,22 +591,24 @@ internal class MXOlmDevice @Inject constructor(
     /**
      * Add an inbound group session to the session store.
      *
-     * @param sessionId                    the session identifier.
-     * @param sessionKey                   base64-encoded secret key.
-     * @param roomId                       the id of the room in which this session will be used.
-     * @param senderKey                    the base64-encoded curve25519 key of the sender.
+     * @param sessionId the session identifier.
+     * @param sessionKey base64-encoded secret key.
+     * @param roomId the id of the room in which this session will be used.
+     * @param senderKey the base64-encoded curve25519 key of the sender.
      * @param forwardingCurve25519KeyChain Devices involved in forwarding this session to us.
-     * @param keysClaimed                  Other keys the sender claims.
-     * @param exportFormat                 true if the megolm keys are in export format
+     * @param keysClaimed Other keys the sender claims.
+     * @param exportFormat true if the megolm keys are in export format
      * @return true if the operation succeeds.
      */
-    fun addInboundGroupSession(sessionId: String,
-                               sessionKey: String,
-                               roomId: String,
-                               senderKey: String,
-                               forwardingCurve25519KeyChain: List<String>,
-                               keysClaimed: Map<String, String>,
-                               exportFormat: Boolean): AddSessionResult {
+    fun addInboundGroupSession(
+            sessionId: String,
+            sessionKey: String,
+            roomId: String,
+            senderKey: String,
+            forwardingCurve25519KeyChain: List<String>,
+            keysClaimed: Map<String, String>,
+            exportFormat: Boolean
+    ): AddSessionResult {
         val candidateSession = OlmInboundGroupSessionWrapper2(sessionKey, exportFormat)
         val existingSessionHolder = tryOrNull { getInboundGroupSession(sessionId, senderKey, roomId) }
         val existingSession = existingSessionHolder?.wrapper
@@ -752,70 +755,77 @@ internal class MXOlmDevice @Inject constructor(
     /**
      * Decrypt a received message with an inbound group session.
      *
-     * @param body      the base64-encoded body of the encrypted message.
-     * @param roomId    the room in which the message was received.
-     * @param timeline  the id of the timeline where the event is decrypted. It is used to prevent replay attack.
+     * @param body the base64-encoded body of the encrypted message.
+     * @param roomId the room in which the message was received.
+     * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
+     * @param eventId the eventId of the message that will be decrypted
      * @param sessionId the session identifier.
      * @param senderKey the base64-encoded curve25519 key of the sender.
-     * @return the decrypting result. Nil if the sessionId is unknown.
+     * @return the decrypting result. Null if the sessionId is unknown.
      */
     @Throws(MXCryptoError::class)
-    suspend fun decryptGroupMessage(body: String,
-                                    roomId: String,
-                                    timeline: String?,
-                                    sessionId: String,
-                                    senderKey: String): OlmDecryptionResult {
+    suspend fun decryptGroupMessage(
+            body: String,
+            roomId: String,
+            timeline: String?,
+            eventId: String,
+            sessionId: String,
+            senderKey: String
+    ): OlmDecryptionResult {
         val sessionHolder = getInboundGroupSession(sessionId, senderKey, roomId)
         val wrapper = sessionHolder.wrapper
         val inboundGroupSession = wrapper.olmInboundGroupSession
                 ?: throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT, "Session is null")
-        // Check that the room id matches the original one for the session. This stops
-        // the HS pretending a message was targeting a different room.
-        if (roomId == wrapper.roomId) {
-            val decryptResult = try {
-                sessionHolder.mutex.withLock {
-                    inboundGroupSession.decryptMessage(body)
-                }
-            } catch (e: OlmException) {
-                Timber.tag(loggerTag.value).e(e, "## decryptGroupMessage () : decryptMessage failed")
-                throw MXCryptoError.OlmError(e)
-            }
-
-            if (timeline?.isNotBlank() == true) {
-                val timelineSet = inboundGroupSessionMessageIndexes.getOrPut(timeline) { mutableSetOf() }
-
-                val messageIndexKey = senderKey + "|" + sessionId + "|" + decryptResult.mIndex
-
-                if (timelineSet.contains(messageIndexKey)) {
-                    val reason = String.format(MXCryptoError.DUPLICATE_MESSAGE_INDEX_REASON, decryptResult.mIndex)
-                    Timber.tag(loggerTag.value).e("## decryptGroupMessage() timelineId=$timeline: $reason")
-                    throw MXCryptoError.Base(MXCryptoError.ErrorType.DUPLICATED_MESSAGE_INDEX, reason)
-                }
-
-                timelineSet.add(messageIndexKey)
-            }
-
-            inboundGroupSessionStore.storeInBoundGroupSession(sessionHolder, sessionId, senderKey)
-            val payload = try {
-                val adapter = MoshiProvider.providesMoshi().adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE)
-                val payloadString = convertFromUTF8(decryptResult.mDecryptedMessage)
-                adapter.fromJson(payloadString)
-            } catch (e: Exception) {
-                Timber.tag(loggerTag.value).e("## decryptGroupMessage() : fails to parse the payload")
-                throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_DECRYPTED_FORMAT, MXCryptoError.BAD_DECRYPTED_FORMAT_TEXT_REASON)
-            }
-
-            return OlmDecryptionResult(
-                    payload,
-                    wrapper.keysClaimed,
-                    senderKey,
-                    wrapper.forwardingCurve25519KeyChain
-            )
-        } else {
+        if (roomId != wrapper.roomId) {
+            // Check that the room id matches the original one for the session. This stops
+            // the HS pretending a message was targeting a different room.
             val reason = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, wrapper.roomId)
             Timber.tag(loggerTag.value).e("## decryptGroupMessage() : $reason")
             throw MXCryptoError.Base(MXCryptoError.ErrorType.INBOUND_SESSION_MISMATCH_ROOM_ID, reason)
         }
+        val decryptResult = try {
+            sessionHolder.mutex.withLock {
+                inboundGroupSession.decryptMessage(body)
+            }
+        } catch (e: OlmException) {
+            Timber.tag(loggerTag.value).e(e, "## decryptGroupMessage () : decryptMessage failed")
+            throw MXCryptoError.OlmError(e)
+        }
+
+        val messageIndexKey = senderKey + "|" + sessionId + "|" + roomId + "|" + decryptResult.mIndex
+        Timber.tag(loggerTag.value).v("##########################################################")
+        Timber.tag(loggerTag.value).v("## decryptGroupMessage() timeline: $timeline")
+        Timber.tag(loggerTag.value).v("## decryptGroupMessage() senderKey: $senderKey")
+        Timber.tag(loggerTag.value).v("## decryptGroupMessage() sessionId: $sessionId")
+        Timber.tag(loggerTag.value).v("## decryptGroupMessage() roomId: $roomId")
+        Timber.tag(loggerTag.value).v("## decryptGroupMessage() eventId: $eventId")
+        Timber.tag(loggerTag.value).v("## decryptGroupMessage() mIndex: ${decryptResult.mIndex}")
+
+        if (timeline?.isNotBlank() == true) {
+            val replayAttackMap = inboundGroupSessionMessageIndexes.getOrPut(timeline) { mutableMapOf() }
+            if (replayAttackMap.contains(messageIndexKey) && replayAttackMap[messageIndexKey] != eventId) {
+                val reason = String.format(MXCryptoError.DUPLICATE_MESSAGE_INDEX_REASON, decryptResult.mIndex)
+                Timber.tag(loggerTag.value).e("## decryptGroupMessage() timelineId=$timeline: $reason")
+                throw MXCryptoError.Base(MXCryptoError.ErrorType.DUPLICATED_MESSAGE_INDEX, reason)
+            }
+            replayAttackMap[messageIndexKey] = eventId
+        }
+        inboundGroupSessionStore.storeInBoundGroupSession(sessionHolder, sessionId, senderKey)
+        val payload = try {
+            val adapter = MoshiProvider.providesMoshi().adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE)
+            val payloadString = convertFromUTF8(decryptResult.mDecryptedMessage)
+            adapter.fromJson(payloadString)
+        } catch (e: Exception) {
+            Timber.tag(loggerTag.value).e("## decryptGroupMessage() : fails to parse the payload")
+            throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_DECRYPTED_FORMAT, MXCryptoError.BAD_DECRYPTED_FORMAT_TEXT_REASON)
+        }
+
+        return OlmDecryptionResult(
+                payload,
+                wrapper.keysClaimed,
+                senderKey,
+                wrapper.forwardingCurve25519KeyChain
+        )
     }
 
     /**
@@ -834,9 +844,9 @@ internal class MXOlmDevice @Inject constructor(
     /**
      * Verify an ed25519 signature on a JSON object.
      *
-     * @param key            the ed25519 key.
+     * @param key the ed25519 key.
      * @param jsonDictionary the JSON object which was signed.
-     * @param signature      the base64-encoded signature to be checked.
+     * @param signature the base64-encoded signature to be checked.
      * @throws Exception the exception
      */
     @Throws(Exception::class)
@@ -859,7 +869,7 @@ internal class MXOlmDevice @Inject constructor(
      * Search an OlmSession.
      *
      * @param theirDeviceIdentityKey the device key
-     * @param sessionId              the session Id
+     * @param sessionId the session Id
      * @return the olm session
      */
     private fun getSessionForDevice(theirDeviceIdentityKey: String, sessionId: String): OlmSessionWrapper? {
@@ -873,9 +883,9 @@ internal class MXOlmDevice @Inject constructor(
      * Extract an InboundGroupSession from the session store and do some check.
      * inboundGroupSessionWithIdError describes the failure reason.
      *
-     * @param roomId    the room where the session is used.
      * @param sessionId the session identifier.
      * @param senderKey the base64-encoded curve25519 key of the sender.
+     * @param roomId the room where the session is used.
      * @return the inbound group session.
      */
     fun getInboundGroupSession(sessionId: String?, senderKey: String?, roomId: String?): InboundGroupSessionHolder {
@@ -905,7 +915,7 @@ internal class MXOlmDevice @Inject constructor(
     /**
      * Determine if we have the keys for a given megolm session.
      *
-     * @param roomId    room in which the message was received
+     * @param roomId room in which the message was received
      * @param senderKey base64-encoded curve25519 key of the sender
      * @param sessionId session identifier
      * @return true if the unbound session keys are known.
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 ab562d954a1f520f3b17f6b77b770da8b31337ec..3f4b633ea01aea5ceceb153f9df232aa298e22c2 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
@@ -19,8 +19,10 @@ package org.matrix.android.sdk.internal.crypto
 import org.matrix.android.sdk.api.auth.data.Credentials
 import javax.inject.Inject
 
-internal class ObjectSigner @Inject constructor(private val credentials: Credentials,
-                                                private val olmDevice: MXOlmDevice) {
+internal class ObjectSigner @Inject constructor(
+        private val credentials: Credentials,
+        private val olmDevice: MXOlmDevice
+) {
 
     /**
      * Sign Object.
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 fe280416ea25eea43d5bdf4815fdfd67d0389e77..4401a07192eaced5b97fc31bed7788ddd3d1a1a9 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
@@ -39,7 +39,7 @@ internal class OlmSessionStore @Inject constructor(private val store: IMXCryptoS
      * Store a session between our own device and another device.
      * This will be called after the session has been created but also every time it has been used
      * in order to persist the correct state for next run
-     * @param olmSessionWrapper   the end-to-end session.
+     * @param olmSessionWrapper the end-to-end session.
      * @param deviceKey the public key of the other device.
      */
     @Synchronized
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
index d7652d07713b60ebf71fb6aae07cae5cf9ff2cf3..6b22cc09d6e8ff37f3ec348b81168a032faa9546 100755
--- 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
@@ -71,7 +71,8 @@ internal class OutgoingKeyRequestManager @Inject constructor(
         private val inboundGroupSessionStore: InboundGroupSessionStore,
         private val sendToDeviceTask: SendToDeviceTask,
         private val deviceListManager: DeviceListManager,
-        private val perSessionBackupQueryRateLimiter: PerSessionBackupQueryRateLimiter) {
+        private val perSessionBackupQueryRateLimiter: PerSessionBackupQueryRateLimiter
+) {
 
     private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
     private val outgoingRequestScope = CoroutineScope(SupervisorJob() + dispatcher)
@@ -180,13 +181,15 @@ internal class OutgoingKeyRequestManager @Inject constructor(
         }
     }
 
-    fun onRoomKeyForwarded(sessionId: String,
-                           algorithm: String,
-                           roomId: String,
-                           senderKey: String,
-                           fromDevice: String?,
-                           fromIndex: Int,
-                           event: Event) {
+    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 {
@@ -208,12 +211,14 @@ internal class OutgoingKeyRequestManager @Inject constructor(
         }
     }
 
-    fun onRoomKeyWithHeld(sessionId: String,
-                          algorithm: String,
-                          roomId: String,
-                          senderKey: String,
-                          fromDevice: String?,
-                          event: Event) {
+    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")
@@ -294,19 +299,19 @@ internal class OutgoingKeyRequestManager @Inject constructor(
         }
         knownRequest.forEach { request ->
             when (request.state) {
-                OutgoingRoomKeyRequestState.UNSENT                               -> {
+                OutgoingRoomKeyRequestState.UNSENT -> {
                     if (request.fromIndex >= localKnownChainIndex) {
                         // we have a good index we can cancel
                         cryptoStore.deleteOutgoingRoomKeyRequest(request.requestId)
                     }
                 }
-                OutgoingRoomKeyRequestState.SENT                                 -> {
+                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                 -> {
+                OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> {
                     // It is already marked to be cancelled
                 }
                 OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> {
@@ -315,7 +320,7 @@ internal class OutgoingKeyRequestManager @Inject constructor(
                         cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING)
                     }
                 }
-                OutgoingRoomKeyRequestState.SENT_THEN_CANCELED                   -> {
+                OutgoingRoomKeyRequestState.SENT_THEN_CANCELED -> {
                     // was already canceled
                     // if we need a better index, should we resend?
                 }
@@ -346,14 +351,14 @@ internal class OutgoingKeyRequestManager @Inject constructor(
         val existing = cryptoStore.getOutgoingRoomKeyRequest(requestBody)
         Timber.tag(loggerTag.value).v("Queueing key request exiting is ${existing?.state}")
         when (existing?.state) {
-            null                                                             -> {
+            null -> {
                 // create a new one
                 cryptoStore.getOrAddOutgoingRoomKeyRequest(requestBody, recipients, fromIndex)
             }
-            OutgoingRoomKeyRequestState.UNSENT                               -> {
+            OutgoingRoomKeyRequestState.UNSENT -> {
                 // nothing it's new or not yet handled
             }
-            OutgoingRoomKeyRequestState.SENT                                 -> {
+            OutgoingRoomKeyRequestState.SENT -> {
                 // it was already requested
                 Timber.tag(loggerTag.value).d("The session ${requestBody.sessionId} is already requested")
                 if (force) {
@@ -366,7 +371,7 @@ internal class OutgoingKeyRequestManager @Inject constructor(
                     }
                 }
             }
-            OutgoingRoomKeyRequestState.CANCELLATION_PENDING                 -> {
+            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)
@@ -375,7 +380,7 @@ internal class OutgoingKeyRequestManager @Inject constructor(
             OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> {
                 // It's already going to resend
             }
-            OutgoingRoomKeyRequestState.SENT_THEN_CANCELED                   -> {
+            OutgoingRoomKeyRequestState.SENT_THEN_CANCELED -> {
                 if (force) {
                     cryptoStore.deleteOutgoingRoomKeyRequest(existing.requestId)
                     cryptoStore.getOrAddOutgoingRoomKeyRequest(requestBody, recipients, fromIndex)
@@ -396,11 +401,11 @@ internal class OutgoingKeyRequestManager @Inject constructor(
         measureTimeMillis {
             toProcess.forEach {
                 when (it.state) {
-                    OutgoingRoomKeyRequestState.UNSENT                               -> handleUnsentRequest(it)
-                    OutgoingRoomKeyRequestState.CANCELLATION_PENDING                 -> handleRequestToCancel(it)
+                    OutgoingRoomKeyRequestState.UNSENT -> handleUnsentRequest(it)
+                    OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> handleRequestToCancel(it)
                     OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> handleRequestToCancelWillResend(it)
                     OutgoingRoomKeyRequestState.SENT_THEN_CANCELED,
-                    OutgoingRoomKeyRequestState.SENT                                 -> {
+                    OutgoingRoomKeyRequestState.SENT -> {
                         // these are filtered out
                     }
                 }
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 c2f494b4b3035b3e118ba8ca3b35edf91faf2d7b..d37e60d28942fbd2d487b50eb33dd3c3e7b704f4 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
@@ -49,7 +49,7 @@ internal class RoomDecryptorProvider @Inject constructor(
      * If we already have a decryptor for the given room and algorithm, return
      * it. Otherwise try to instantiate it.
      *
-     * @param roomId    the room id
+     * @param roomId the room id
      * @param algorithm the crypto algorithm
      * @return the decryptor
      * // TODO Create another method for the case of roomId is null
@@ -85,7 +85,7 @@ internal class RoomDecryptorProvider @Inject constructor(
                         }
                     }
                 }
-                else                      -> olmDecryptionFactory.create()
+                else -> olmDecryptionFactory.create()
             }
             if (!roomId.isNullOrEmpty()) {
                 synchronized(roomDecryptors) {
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 1a8c160d9c313c8fba72777234193a44dce431a8..9f6714cc458bd5573ba3ee208156bad826a7e64e 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
@@ -49,8 +49,8 @@ internal class RoomEncryptorsStore @Inject constructor(
             } else {
                 val alg: IMXEncrypting? = when (cryptoStore.getRoomAlgorithm(roomId)) {
                     MXCRYPTO_ALGORITHM_MEGOLM -> megolmEncryptionFactory.create(roomId)
-                    MXCRYPTO_ALGORITHM_OLM    -> olmEncryptionFactory.create(roomId)
-                    else                      -> null
+                    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
index 6fb6914206f9e97000915ab0262117c435278c27..a79e1a89012a7e3d4b02aa18825111cfb6047f27 100644
--- 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
@@ -150,14 +150,14 @@ internal class SecretShareManager @Inject constructor(
             // we can share the secret
 
             val secretValue = when (secretName) {
-                MASTER_KEY_SSSS_NAME       -> cryptoStore.getCrossSigningPrivateKeys()?.master
+                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
+                else -> null
             }
             if (secretValue == null) {
                 Timber.tag(loggerTag.value)
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 c728f1b6827a427dda5124d3398b9615b0b5bce2..c263192fee5e0a5929d331e30d131a9038e4e656 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
@@ -39,7 +39,8 @@ private val loggerTag = LoggerTag("EnsureOlmSessionsForDevicesAction", LoggerTag
 internal class EnsureOlmSessionsForDevicesAction @Inject constructor(
         private val olmDevice: MXOlmDevice,
         private val coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val oneTimeKeysForUsersDeviceTask: ClaimOneTimeKeysForUsersDeviceTask) {
+        private val oneTimeKeysForUsersDeviceTask: ClaimOneTimeKeysForUsersDeviceTask
+) {
 
     private val ensureMutex = Mutex()
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt
index fc211537a6872f02dece4f11d9ce77e82df9ec99..da0952466857a6f0712ee6008d171fad9365c266 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt
@@ -23,13 +23,15 @@ import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import timber.log.Timber
 import javax.inject.Inject
 
-internal class EnsureOlmSessionsForUsersAction @Inject constructor(private val olmDevice: MXOlmDevice,
-                                                                   private val cryptoStore: IMXCryptoStore,
-                                                                   private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction) {
+internal class EnsureOlmSessionsForUsersAction @Inject constructor(
+        private val olmDevice: MXOlmDevice,
+        private val cryptoStore: IMXCryptoStore,
+        private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction
+) {
 
     /**
      * Try to make sure we have established olm sessions for the given users.
-     * @param users    a list of user ids.
+     * @param users a list of user ids.
      */
     suspend fun handle(users: List<String>): MXUsersDevicesMap<MXOlmSessionResult> {
         Timber.v("## ensureOlmSessionsForUsers() : ensureOlmSessionsForUsers $users")
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 22c4e59b1899dd3f23e74cf17ad2019f0df034e7..f6ab96aee68033c95460b670ecc194b403003e89 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
@@ -33,11 +33,12 @@ import javax.inject.Inject
 
 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,
+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,
 ) {
 
     /**
@@ -45,14 +46,16 @@ internal class MegolmSessionDataImporter @Inject constructor(private val olmDevi
      * Must be call on the crypto coroutine thread
      *
      * @param megolmSessionsData megolm sessions.
-     * @param fromBackup         true if the imported keys are already backed up on the server.
-     * @param progressListener   the progress listener
+     * @param fromBackup true if the imported keys are already backed up on the server.
+     * @param progressListener the progress listener
      * @return import room keys result
      */
     @WorkerThread
-    fun handle(megolmSessionsData: List<MegolmSessionData>,
-               fromBackup: Boolean,
-               progressListener: ProgressListener?): ImportRoomKeysResult {
+    fun handle(
+            megolmSessionsData: List<MegolmSessionData>,
+            fromBackup: Boolean,
+            progressListener: ProgressListener?
+    ): ImportRoomKeysResult {
         val t0 = clock.epochMillis()
 
         val totalNumbersOfKeys = megolmSessionsData.size
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MessageEncrypter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MessageEncrypter.kt
index 9bbbab4992a4b1bb2bb676b3edbe1227e7c61419..eff21328204cd71bafec416d76ab5035aef6d321 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MessageEncrypter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MessageEncrypter.kt
@@ -36,13 +36,14 @@ internal class MessageEncrypter @Inject constructor(
         private val userId: String,
         @DeviceId
         private val deviceId: String?,
-        private val olmDevice: MXOlmDevice) {
+        private val olmDevice: MXOlmDevice
+) {
     /**
      * Encrypt an event payload for a list of devices.
      * This method must be called from the getCryptoHandler() thread.
      *
      * @param payloadFields fields to include in the encrypted payload.
-     * @param deviceInfos   list of device infos to encrypt for.
+     * @param deviceInfos list of device infos to encrypt for.
      * @return the content for an m.room.encrypted event.
      */
     suspend fun encryptMessage(payloadFields: Content, deviceInfos: List<CryptoDeviceInfo>): EncryptedMessage {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/SetDeviceVerificationAction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/SetDeviceVerificationAction.kt
index 60181138fb976f820119caecfc9edcd8570c3acb..6028b1a5a2a4ca6de7172a9774292149fa2dec2c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/SetDeviceVerificationAction.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/SetDeviceVerificationAction.kt
@@ -26,7 +26,8 @@ import javax.inject.Inject
 internal class SetDeviceVerificationAction @Inject constructor(
         private val cryptoStore: IMXCryptoStore,
         @UserId private val userId: String,
-        private val defaultKeysBackupService: DefaultKeysBackupService) {
+        private val defaultKeysBackupService: DefaultKeysBackupService
+) {
 
     fun handle(trustLevel: DeviceTrustLevel, userId: String, deviceId: String) {
         val device = cryptoStore.getUserDevice(userId, deviceId)
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 34006ecfde5910ff4b5684a4ec769ef0609a41e5..6847a463690c369774fd09d6efb7bf0c52bdabc4 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
@@ -29,7 +29,7 @@ internal interface IMXDecrypting {
     /**
      * Decrypt an event.
      *
-     * @param event    the raw 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.
      * @return the decryption information, or an error
      */
@@ -40,6 +40,7 @@ internal interface IMXDecrypting {
      * Handle a key event.
      *
      * @param event the key event.
+     * @param defaultKeysBackupService the keys backup service
      */
     fun onRoomKeyEvent(event: Event, defaultKeysBackupService: DefaultKeysBackupService) {}
 }
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 1d8412020876990c6631da60b05743409f676f4d..73ce5a5004b10ca227b8d50362fe6881546dbb69 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
@@ -27,8 +27,8 @@ internal interface IMXEncrypting {
      * Encrypt an event content according to the configuration of the room.
      *
      * @param eventContent the content of the event.
-     * @param eventType    the type of the event.
-     * @param userIds      the room members the event will be sent to.
+     * @param eventType the type of the event.
+     * @param userIds the room members the event will be sent to.
      * @return the encrypted content
      */
     suspend fun encryptEventContent(eventContent: Content, eventType: String, userIds: List<String>): Content
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXGroupEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXGroupEncryption.kt
index 6f488def0af0d366df361e76999efcfa1e0f637f..9ec78f37cfee18542fb3a25da3917896b0a8f445 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXGroupEncryption.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXGroupEncryption.kt
@@ -38,15 +38,17 @@ internal interface IMXGroupEncryption {
      * Re-shares a session key with devices if the key has already been
      * sent to them.
      *
-     * @param sessionId The id of the outbound session to share.
+     * @param groupSessionId The id of the outbound session to share.
      * @param userId The id of the user who owns the target device.
      * @param deviceId The id of the target device.
      * @param senderKey The key of the originating device for the session.
      *
      * @return true in case of success
      */
-    suspend fun reshareKey(groupSessionId: String,
-                           userId: String,
-                           deviceId: String,
-                           senderKey: String): Boolean
+    suspend fun reshareKey(
+            groupSessionId: String,
+            userId: String,
+            deviceId: String,
+            senderKey: String
+    ): Boolean
 }
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 8321b73b758c2baa34dc780cddf5bbc22199b1cb..141d6f74cd0b23525356af59790b459dbeceba3e 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
@@ -78,6 +78,7 @@ internal class MXMegolmDecryption(
                     encryptedEventContent.ciphertext,
                     event.roomId,
                     timeline,
+                    eventId = event.eventId.orEmpty(),
                     encryptedEventContent.sessionId,
                     encryptedEventContent.senderKey
             )
@@ -148,7 +149,8 @@ internal class MXMegolmDecryption(
                                         throw MXCryptoError.Base(
                                                 MXCryptoError.ErrorType.KEYS_WITHHELD,
                                                 withHeldInfo.code?.value ?: "",
-                                                withHeldInfo.reason)
+                                                withHeldInfo.reason
+                                        )
                                     }
 
                                     if (requestKeysOnFail) {
@@ -176,6 +178,7 @@ internal class MXMegolmDecryption(
      * Handle a key event.
      *
      * @param event the key event.
+     * @param defaultKeysBackupService the keys backup service
      */
     override fun onRoomKeyEvent(event: Event, defaultKeysBackupService: DefaultKeysBackupService) {
         Timber.tag(loggerTag.value).v("onRoomKeyEvent()")
@@ -247,9 +250,9 @@ internal class MXMegolmDecryption(
         )
 
         when (addSessionResult) {
-            is MXOlmDevice.AddSessionResult.Imported               -> addSessionResult.ratchetIndex
+            is MXOlmDevice.AddSessionResult.Imported -> addSessionResult.ratchetIndex
             is MXOlmDevice.AddSessionResult.NotImportedHigherIndex -> addSessionResult.newIndex
-            else                                                   -> null
+            else -> null
         }?.let { index ->
             if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
                 val fromDevice = (event.content?.get("sender_key") as? String)?.let { senderDeviceIdentityKey ->
@@ -266,7 +269,8 @@ internal class MXMegolmDecryption(
                         senderKey = senderKey,
                         fromIndex = index,
                         fromDevice = fromDevice,
-                        event = event)
+                        event = event
+                )
 
                 cryptoStore.saveIncomingForwardKeyAuditTrail(
                         roomId = roomKeyContent.roomId,
@@ -275,7 +279,8 @@ internal class MXMegolmDecryption(
                         algorithm = roomKeyContent.algorithm ?: "",
                         userId = event.senderId ?: "",
                         deviceId = fromDevice ?: "",
-                        chainIndex = index.toLong())
+                        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)
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 096773a9594772d050829bf9cf7a62a9d073d844..81a6fb28c06e4fc30bdc24c7b5f62fbc5995c1c0 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
@@ -35,6 +35,7 @@ internal class MXMegolmDecryptionFactory @Inject constructor(
                 olmDevice,
                 outgoingKeyRequestManager,
                 cryptoStore,
-                eventsManager)
+                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 79e907945fc9e403590f2377097aad29857e700d..7bfbae6edf5ab194de33dec1054e3fef5b3c2d2b 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
@@ -84,9 +84,11 @@ internal class MXMegolmEncryption(
     private var sessionRotationPeriodMsgs: Int = 100
     private var sessionRotationPeriodMs: Int = 7 * 24 * 3600 * 1000
 
-    override suspend fun encryptEventContent(eventContent: Content,
-                                             eventType: String,
-                                             userIds: List<String>): Content {
+    override suspend fun encryptEventContent(
+            eventContent: Content,
+            eventType: String,
+            userIds: List<String>
+    ): Content {
         val ts = clock.epochMillis()
         Timber.tag(loggerTag.value).v("encryptEventContent : getDevicesInRoom")
         val devices = getDevicesInRoom(userIds)
@@ -198,11 +200,13 @@ internal class MXMegolmEncryption(
     /**
      * Share the device key to a list of users.
      *
-     * @param session        the session info
+     * @param session the session info
      * @param devicesByUsers the devices map
      */
-    private suspend fun shareKey(session: MXOutboundSessionInfo,
-                                 devicesByUsers: Map<String, List<CryptoDeviceInfo>>) {
+    private suspend fun shareKey(
+            session: MXOutboundSessionInfo,
+            devicesByUsers: Map<String, List<CryptoDeviceInfo>>
+    ) {
         // nothing to send, the task is done
         if (devicesByUsers.isEmpty()) {
             Timber.tag(loggerTag.value).v("shareKey() : nothing more to do")
@@ -227,11 +231,13 @@ internal class MXMegolmEncryption(
     /**
      * Share the device keys of a an user.
      *
-     * @param session       the session info
+     * @param session the session info
      * @param devicesByUser the devices map
      */
-    private suspend fun shareUserDevicesKey(session: MXOutboundSessionInfo,
-                                            devicesByUser: Map<String, List<CryptoDeviceInfo>>) {
+    private suspend fun shareUserDevicesKey(
+            session: MXOutboundSessionInfo,
+            devicesByUser: Map<String, List<CryptoDeviceInfo>>
+    ) {
         val sessionKey = olmDevice.getSessionKey(session.sessionId)
         val chainIndex = olmDevice.getMessageIndex(session.sessionId)
 
@@ -321,10 +327,12 @@ internal class MXMegolmEncryption(
         }
     }
 
-    private suspend fun notifyKeyWithHeld(targets: List<UserDevice>,
-                                          sessionId: String,
-                                          senderKey: String?,
-                                          code: WithHeldCode) {
+    private suspend fun notifyKeyWithHeld(
+            targets: List<UserDevice>,
+            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}" }}"
@@ -387,7 +395,7 @@ internal class MXMegolmEncryption(
      * Get the list of devices which can encrypt data to.
      * This method must be called in getDecryptingThreadHandler() thread.
      *
-     * @param userIds  the user ids whose devices must be checked.
+     * @param userIds the user ids whose devices must be checked.
      */
     private suspend fun getDevicesInRoom(userIds: List<String>): DeviceInRoomInfo {
         // We are happy to use a cached version here: we assume that if we already
@@ -435,10 +443,12 @@ internal class MXMegolmEncryption(
         }
     }
 
-    override suspend fun reshareKey(groupSessionId: String,
-                                    userId: String,
-                                    deviceId: String,
-                                    senderKey: String): Boolean {
+    override suspend fun reshareKey(
+            groupSessionId: String,
+            userId: String,
+            deviceId: String,
+            senderKey: String
+    ): Boolean {
         Timber.tag(loggerTag.value).i("process reshareKey for $groupSessionId to $userId:$deviceId")
         val deviceInfo = cryptoStore.getUserDevice(userId, deviceId) ?: return false
                 .also { Timber.tag(loggerTag.value).w("reshareKey: Device not found") }
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 61ad345c62ca1b62d3ac399f19ea8d59849b7187..30fd403ce8588c32299d174986088c46676304c1 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
@@ -23,7 +23,8 @@ import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 internal class SharedWithHelper(
         private val roomId: String,
         private val sessionId: String,
-        private val cryptoStore: IMXCryptoStore) {
+        private val cryptoStore: IMXCryptoStore
+) {
 
     fun sharedWithDevices(): MXUsersDevicesMap<Int> {
         return cryptoStore.getSharedWithInfo(roomId, sessionId)
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 1e66fe84c96b51135a72e267ae18e0f271468af5..219cadac464f896826fb0b6425322e7f786762f3 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
@@ -38,7 +38,8 @@ internal class MXOlmDecryption(
         // The olm device interface
         private val olmDevice: MXOlmDevice,
         // the matrix userId
-        private val userId: String) :
+        private val userId: String
+) :
         IMXDecrypting {
 
     @Throws(MXCryptoError::class)
@@ -180,8 +181,8 @@ internal class MXOlmDecryption(
     /**
      * Attempt to decrypt an Olm message.
      *
+     * @param message message object, with 'type' and 'body' fields.
      * @param theirDeviceIdentityKey the Curve25519 identity key of the sender.
-     * @param message                message object, with 'type' and 'body' fields.
      * @return payload, if decrypted successfully.
      */
     private suspend fun decryptMessage(message: JsonDict, theirDeviceIdentityKey: String): String? {
@@ -190,9 +191,9 @@ internal class MXOlmDecryption(
         val messageBody = message["body"] as? String ?: return null
         val messageType = when (val typeAsVoid = message["type"]) {
             is Double -> typeAsVoid.toInt()
-            is Int    -> typeAsVoid
-            is Long   -> typeAsVoid.toInt()
-            else      -> return null
+            is Int -> typeAsVoid
+            is Long -> typeAsVoid.toInt()
+            else -> return null
         }
 
         // Try each session in turn
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 d5c5e85e41a1e37ed5ff6874fb040f47666edb4b..a50ac8ca8a82fe440c79490ca8e2c1bd0cfe9827 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
@@ -20,8 +20,10 @@ import org.matrix.android.sdk.internal.crypto.MXOlmDevice
 import org.matrix.android.sdk.internal.di.UserId
 import javax.inject.Inject
 
-internal class MXOlmDecryptionFactory @Inject constructor(private val olmDevice: MXOlmDevice,
-                                                          @UserId private val userId: String) {
+internal class MXOlmDecryptionFactory @Inject constructor(
+        private val olmDevice: MXOlmDevice,
+        @UserId private val userId: String
+) {
 
     fun create(): MXOlmDecryption {
         return MXOlmDecryption(
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 3c9706abe18e31ddadeb5c39cf9b8332cf65c895..fb70e23b03c66edf3d87587681ca0abbbfb02c14 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
@@ -32,7 +32,8 @@ internal class MXOlmEncryption(
         private val cryptoStore: IMXCryptoStore,
         private val messageEncrypter: MessageEncrypter,
         private val deviceListManager: DeviceListManager,
-        private val ensureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction) :
+        private val ensureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction
+) :
         IMXEncrypting {
 
     override suspend fun encryptEventContent(eventContent: Content, eventType: String, userIds: List<String>): Content {
@@ -70,7 +71,7 @@ internal class MXOlmEncryption(
     /**
      * Ensure that the session.
      *
-     * @param users    the user ids list
+     * @param users the user ids list
      */
     private suspend fun ensureSession(users: List<String>) {
         deviceListManager.downloadKeys(users, false)
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 44e55900e4ada7db382ba541a5c51989a72a3d68..012886203ec19015558deba7158c1859c5b48a9a 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
@@ -24,12 +24,14 @@ import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import javax.inject.Inject
 
-internal class MXOlmEncryptionFactory @Inject constructor(private val olmDevice: MXOlmDevice,
-                                                          private val cryptoStore: IMXCryptoStore,
-                                                          private val messageEncrypter: MessageEncrypter,
-                                                          private val deviceListManager: DeviceListManager,
-                                                          private val coroutineDispatchers: MatrixCoroutineDispatchers,
-                                                          private val ensureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction) {
+internal class MXOlmEncryptionFactory @Inject constructor(
+        private val olmDevice: MXOlmDevice,
+        private val cryptoStore: IMXCryptoStore,
+        private val messageEncrypter: MessageEncrypter,
+        private val deviceListManager: DeviceListManager,
+        private val coroutineDispatchers: MatrixCoroutineDispatchers,
+        private val ensureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction
+) {
 
     fun create(roomId: String): MXOlmEncryption {
         return MXOlmEncryption(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/api/CryptoApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/api/CryptoApi.kt
index f21f5e05e1416d081cdf9e0d54bba9e3d9e1bed9..d5a8bdfd7cb62f17b4be13f66a34b18a7c6df820 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/api/CryptoApi.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/api/CryptoApi.kt
@@ -103,7 +103,7 @@ internal interface CryptoApi {
      * Claim one-time keys.
      * Doc: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-keys-claim
      *
-     * @param params the params.
+     * @param body the Json body.
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "keys/claim")
     suspend fun claimOneTimeKeysForUsersDevices(@Body body: KeysClaimBody): KeysClaimResponse
@@ -112,36 +112,42 @@ internal interface CryptoApi {
      * Send an event to a specific list of devices
      * Doc: https://matrix.org/docs/spec/client_server/r0.4.0.html#put-matrix-client-r0-sendtodevice-eventtype-txnid
      *
-     * @param eventType     the type of event to send
+     * @param eventType the type of event to send
      * @param transactionId the transaction ID for this event
-     * @param body          the body
+     * @param body the body
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "sendToDevice/{eventType}/{txnId}")
-    suspend fun sendToDevice(@Path("eventType") eventType: String,
-                             @Path("txnId") transactionId: String,
-                             @Body body: SendToDeviceBody)
+    suspend fun sendToDevice(
+            @Path("eventType") eventType: String,
+            @Path("txnId") transactionId: String,
+            @Body body: SendToDeviceBody
+    )
 
     /**
      * Delete a device.
      * Doc: https://matrix.org/docs/spec/client_server/r0.4.0.html#delete-matrix-client-r0-devices-deviceid
      *
      * @param deviceId the device id
-     * @param params   the deletion parameters
+     * @param params the deletion parameters
      */
     @HTTP(path = NetworkConstants.URI_API_PREFIX_PATH_R0 + "devices/{device_id}", method = "DELETE", hasBody = true)
-    suspend fun deleteDevice(@Path("device_id") deviceId: String,
-                             @Body params: DeleteDeviceParams)
+    suspend fun deleteDevice(
+            @Path("device_id") deviceId: String,
+            @Body params: DeleteDeviceParams
+    )
 
     /**
      * Update the device information.
      * Doc: https://matrix.org/docs/spec/client_server/r0.4.0.html#put-matrix-client-r0-devices-deviceid
      *
      * @param deviceId the device id
-     * @param params   the params
+     * @param params the params
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "devices/{device_id}")
-    suspend fun updateDeviceInfo(@Path("device_id") deviceId: String,
-                                 @Body params: UpdateDeviceInfoBody)
+    suspend fun updateDeviceInfo(
+            @Path("device_id") deviceId: String,
+            @Body params: UpdateDeviceInfoBody
+    )
 
     /**
      * Get the update devices list from two sync token.
@@ -151,6 +157,8 @@ internal interface CryptoApi {
      * @param newToken the up-to token.
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "keys/changes")
-    suspend fun getKeyChanges(@Query("from") oldToken: String,
-                              @Query("to") newToken: String): KeyChangesResponse
+    suspend fun getKeyChanges(
+            @Query("from") oldToken: String,
+            @Query("to") newToken: String
+    ): KeyChangesResponse
 }
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 b4cbd15109b5ca457ee426472dc50f7a319aa69c..37c8e755ff81632a034db67348ea448afac54f9e 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
@@ -41,10 +41,12 @@ internal object MXEncryptedAttachments {
     private const val SECRET_KEY_SPEC_ALGORITHM = "AES"
     private const val MESSAGE_DIGEST_ALGORITHM = "SHA-256"
 
-    fun encrypt(clearStream: InputStream,
-                outputFile: File,
-                clock: Clock,
-                progress: ((current: Int, total: Int) -> Unit)): EncryptedFileInfo {
+    fun encrypt(
+            clearStream: InputStream,
+            outputFile: File,
+            clock: Clock,
+            progress: ((current: Int, total: Int) -> Unit)
+    ): EncryptedFileInfo {
         val t0 = clock.epochMillis()
         val secureRandom = SecureRandom()
         val initVectorBytes = ByteArray(16) { 0.toByte() }
@@ -159,6 +161,7 @@ internal object MXEncryptedAttachments {
      * Encrypt an attachment stream.
      * DO NOT USE for big files, it will load all in memory
      * @param attachmentStream the attachment stream. Will be closed after this method call.
+     * @param clock a clock to retrieve current time
      * @return the encryption file info
      */
     fun encryptAttachment(attachmentStream: InputStream, clock: Clock): EncryptionResult {
@@ -231,13 +234,15 @@ internal object MXEncryptedAttachments {
      *
      * @param attachmentStream the attachment stream. Will be closed after this method call.
      * @param elementToDecrypt the elementToDecrypt info
-     * @param outputStream     the outputStream where the decrypted attachment will be write.
+     * @param outputStream the outputStream where the decrypted attachment will be write.
+     * @param clock a clock to retrieve current time
      * @return true in case of success, false in case of error
      */
-    fun decryptAttachment(attachmentStream: InputStream?,
-                          elementToDecrypt: ElementToDecrypt?,
-                          outputStream: OutputStream,
-                          clock: Clock
+    fun decryptAttachment(
+            attachmentStream: InputStream?,
+            elementToDecrypt: ElementToDecrypt?,
+            outputStream: OutputStream,
+            clock: Clock
     ): Boolean {
         // sanity checks
         if (null == attachmentStream || elementToDecrypt == null) {
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
index 4fa355cd2a787511b5463d9abf70e526a35a3376..3218b9994839f72d5d01c150881bf8928b335f16 100644
--- 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
@@ -53,13 +53,13 @@ internal class CrossSigningOlm @Inject constructor(
     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.SELF -> myKeys?.selfSigningKey()
+            KeyType.USER -> myKeys?.userKey()
             KeyType.MASTER -> myKeys?.masterKey()
         }?.unpaddedBase64PublicKey
         val pkSigning = when (type) {
-            KeyType.SELF   -> selfSigningPkSigning
-            KeyType.USER   -> userPkSigning
+            KeyType.SELF -> selfSigningPkSigning
+            KeyType.USER -> userPkSigning
             KeyType.MASTER -> masterPkSigning
         }
         if (pubKey == null || pkSigning == null) {
@@ -76,8 +76,8 @@ internal class CrossSigningOlm @Inject constructor(
                 ?: throw NoSuchElementException("Cross Signing not configured")
         val myUserID = myKeys.userId
         val pubKey = when (type) {
-            KeyType.SELF   -> myKeys.selfSigningKey()
-            KeyType.USER   -> myKeys.userKey()
+            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
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 6c198abc2ed7db270b448dca000cb632468f3095..e466def1a164ea9bd858d93936850e6d80173db7 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
@@ -261,9 +261,10 @@ internal class DefaultCrossSigningService @Inject constructor(
                 }
     }
 
-    override fun checkTrustFromPrivateKeys(masterKeyPrivateKey: String?,
-                                           uskKeyPrivateKey: String?,
-                                           sskPrivateKey: String?
+    override fun checkTrustFromPrivateKeys(
+            masterKeyPrivateKey: String?,
+            uskKeyPrivateKey: String?,
+            sskPrivateKey: String?
     ): UserTrustResult {
         val mxCrossSigningInfo = getMyCrossSigningKeys() ?: return UserTrustResult.CrossSigningNotConfigured(userId)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt
index 74f0f5745d39d0745b923ef6f177b392e86f1dc6..f1dc060e10e6b21ce00d4876512c8483ec5f627c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt
@@ -149,7 +149,7 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
             val trusts = otherInfos.mapValues { entry ->
                 when (entry.key) {
                     myUserId -> myTrustResult
-                    else     -> {
+                    else -> {
                         crossSigningService.checkOtherMSKTrusted(myCrossSigningInfo, entry.value).also {
                             Timber.v("## CrossSigning - user:${entry.key} result:$it")
                         }
@@ -276,10 +276,12 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses
                 }
     }
 
-    private fun computeRoomShield(myCrossSigningInfo: MXCrossSigningInfo?,
-                                  cryptoRealm: Realm,
-                                  activeMemberUserIds: List<String>,
-                                  roomSummaryEntity: RoomSummaryEntity): RoomEncryptionTrustLevel {
+    private fun computeRoomShield(
+            myCrossSigningInfo: MXCrossSigningInfo?,
+            cryptoRealm: Realm,
+            activeMemberUserIds: List<String>,
+            roomSummaryEntity: RoomSummaryEntity
+    ): RoomEncryptionTrustLevel {
         Timber.v("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} -> ${activeMemberUserIds.logLimit()}")
         // The set of “all users” depends on the type of room:
         // For regular / topic rooms which have more than 2 members (including yourself) are considered when decorating a room
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 5ea4695da29b4bcf73a372cc338c6b88909db9b2..5eaa106af3cc732c38953816dd1c94f505aa97ca 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
@@ -137,17 +137,11 @@ internal class DefaultKeysBackupService @Inject constructor(
 
     private var keysBackupStateListener: KeysBackupStateListener? = null
 
-    override val isEnabled: Boolean
-        get() = keysBackupStateManager.isEnabled
+    override fun isEnabled(): Boolean = keysBackupStateManager.isEnabled
 
-    override val isStucked: Boolean
-        get() = keysBackupStateManager.isStucked
+    override fun isStuck(): Boolean = keysBackupStateManager.isStuck
 
-    override val state: KeysBackupState
-        get() = keysBackupStateManager.state
-
-    override val currentBackupVersion: String?
-        get() = keysBackupVersion?.version
+    override fun getState(): KeysBackupState = keysBackupStateManager.state
 
     override fun addListener(listener: KeysBackupStateListener) {
         keysBackupStateManager.addListener(listener)
@@ -157,9 +151,11 @@ internal class DefaultKeysBackupService @Inject constructor(
         keysBackupStateManager.removeListener(listener)
     }
 
-    override fun prepareKeysBackupVersion(password: String?,
-                                          progressListener: ProgressListener?,
-                                          callback: MatrixCallback<MegolmBackupCreationInfo>) {
+    override fun prepareKeysBackupVersion(
+            password: String?,
+            progressListener: ProgressListener?,
+            callback: MatrixCallback<MegolmBackupCreationInfo>
+    ) {
         cryptoCoroutineScope.launch(coroutineDispatchers.io) {
             try {
                 val olmPkDecryption = OlmPkDecryption()
@@ -233,8 +229,10 @@ internal class DefaultKeysBackupService @Inject constructor(
         }
     }
 
-    override fun createKeysBackupVersion(keysBackupCreationInfo: MegolmBackupCreationInfo,
-                                         callback: MatrixCallback<KeysVersion>) {
+    override fun createKeysBackupVersion(
+            keysBackupCreationInfo: MegolmBackupCreationInfo,
+            callback: MatrixCallback<KeysVersion>
+    ) {
         @Suppress("UNCHECKED_CAST")
         val createKeysBackupVersionBody = CreateKeysBackupVersionBody(
                 algorithm = keysBackupCreationInfo.algorithm,
@@ -291,7 +289,7 @@ internal class DefaultKeysBackupService @Inject constructor(
                         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) {
+                                if (getState() == KeysBackupState.Unknown) {
                                     checkAndStartKeysBackup()
                                 }
                             }
@@ -324,7 +322,7 @@ internal class DefaultKeysBackupService @Inject constructor(
         // val hashServer = keysBackupData?.backupLastServerHash
 
         return when {
-            totalNumberOfKeysLocally < totalNumberOfKeysServer  -> {
+            totalNumberOfKeysLocally < totalNumberOfKeysServer -> {
                 // Server contains more keys than this device
                 true
             }
@@ -333,7 +331,7 @@ internal class DefaultKeysBackupService @Inject constructor(
                 // TODO We have not found any algorithm to determine if a restore is recommended here. Return false for the moment
                 false
             }
-            else                                                -> false
+            else -> false
         }
     }
 
@@ -345,9 +343,11 @@ internal class DefaultKeysBackupService @Inject constructor(
         return cryptoStore.inboundGroupSessionsCount(true)
     }
 
-    override fun backupAllGroupSessions(progressListener: ProgressListener?,
-                                        callback: MatrixCallback<Unit>?) {
-        if (!isEnabled || backupOlmPkEncryption == null || keysBackupVersion == null) {
+    override fun backupAllGroupSessions(
+            progressListener: ProgressListener?,
+            callback: MatrixCallback<Unit>?
+    ) {
+        if (!isEnabled() || backupOlmPkEncryption == null || keysBackupVersion == null) {
             callback?.onFailure(Throwable("Backup not enabled"))
             return
         }
@@ -383,7 +383,7 @@ internal class DefaultKeysBackupService @Inject constructor(
                                 }
 
                                 // If backup is finished, notify the main listener
-                                if (state === KeysBackupState.ReadyToBackUp) {
+                                if (getState() === KeysBackupState.ReadyToBackUp) {
                                     backupAllGroupSessionsCallback?.onSuccess(Unit)
                                     resetBackupAllGroupSessionsListeners()
                                 }
@@ -397,8 +397,10 @@ internal class DefaultKeysBackupService @Inject constructor(
         })
     }
 
-    override fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult,
-                                    callback: MatrixCallback<KeysBackupVersionTrust>) {
+    override fun getKeysBackupTrust(
+            keysBackupVersion: KeysVersionResult,
+            callback: MatrixCallback<KeysBackupVersionTrust>
+    ) {
         // TODO Validate with François that this is correct
         object : Task<KeysVersionResult, KeysBackupVersionTrust> {
             override suspend fun execute(params: KeysVersionResult): KeysBackupVersionTrust {
@@ -505,9 +507,11 @@ internal class DefaultKeysBackupService @Inject constructor(
         )
     }
 
-    override fun trustKeysBackupVersion(keysBackupVersion: KeysVersionResult,
-                                        trust: Boolean,
-                                        callback: MatrixCallback<Unit>) {
+    override fun trustKeysBackupVersion(
+            keysBackupVersion: KeysVersionResult,
+            trust: Boolean,
+            callback: MatrixCallback<Unit>
+    ) {
         Timber.v("trustKeyBackupVersion: $trust, version ${keysBackupVersion.version}")
 
         // Get auth data to update it
@@ -589,9 +593,11 @@ internal class DefaultKeysBackupService @Inject constructor(
         }
     }
 
-    override fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult,
-                                                       recoveryKey: String,
-                                                       callback: MatrixCallback<Unit>) {
+    override fun trustKeysBackupVersionWithRecoveryKey(
+            keysBackupVersion: KeysVersionResult,
+            recoveryKey: String,
+            callback: MatrixCallback<Unit>
+    ) {
         Timber.v("trustKeysBackupVersionWithRecoveryKey: version ${keysBackupVersion.version}")
 
         cryptoCoroutineScope.launch(coroutineDispatchers.io) {
@@ -608,9 +614,11 @@ internal class DefaultKeysBackupService @Inject constructor(
         }
     }
 
-    override fun trustKeysBackupVersionWithPassphrase(keysBackupVersion: KeysVersionResult,
-                                                      password: String,
-                                                      callback: MatrixCallback<Unit>) {
+    override fun trustKeysBackupVersionWithPassphrase(
+            keysBackupVersion: KeysVersionResult,
+            password: String,
+            callback: MatrixCallback<Unit>
+    ) {
         Timber.v("trustKeysBackupVersionWithPassphrase: version ${keysBackupVersion.version}")
 
         cryptoCoroutineScope.launch(coroutineDispatchers.io) {
@@ -628,7 +636,7 @@ internal class DefaultKeysBackupService @Inject constructor(
         }
     }
 
-    override fun onSecretKeyGossip(secret: String) {
+    fun onSecretKeyGossip(secret: String) {
         Timber.i("## CrossSigning - onSecretKeyGossip")
 
         cryptoCoroutineScope.launch(coroutineDispatchers.io) {
@@ -707,12 +715,14 @@ internal class DefaultKeysBackupService @Inject constructor(
         progressListener.onProgress(backedUpKeys, total)
     }
 
-    override fun restoreKeysWithRecoveryKey(keysVersionResult: KeysVersionResult,
-                                            recoveryKey: String,
-                                            roomId: String?,
-                                            sessionId: String?,
-                                            stepProgressListener: StepProgressListener?,
-                                            callback: MatrixCallback<ImportRoomKeysResult>) {
+    override fun restoreKeysWithRecoveryKey(
+            keysVersionResult: KeysVersionResult,
+            recoveryKey: String,
+            roomId: String?,
+            sessionId: String?,
+            stepProgressListener: StepProgressListener?,
+            callback: MatrixCallback<ImportRoomKeysResult>
+    ) {
         Timber.v("restoreKeysWithRecoveryKey: From backup version: ${keysVersionResult.version}")
 
         cryptoCoroutineScope.launch(coroutineDispatchers.io) {
@@ -806,12 +816,14 @@ internal class DefaultKeysBackupService @Inject constructor(
         }
     }
 
-    override fun restoreKeyBackupWithPassword(keysBackupVersion: KeysVersionResult,
-                                              password: String,
-                                              roomId: String?,
-                                              sessionId: String?,
-                                              stepProgressListener: StepProgressListener?,
-                                              callback: MatrixCallback<ImportRoomKeysResult>) {
+    override fun restoreKeyBackupWithPassword(
+            keysBackupVersion: KeysVersionResult,
+            password: String,
+            roomId: String?,
+            sessionId: String?,
+            stepProgressListener: StepProgressListener?,
+            callback: MatrixCallback<ImportRoomKeysResult>
+    ) {
         Timber.v("[MXKeyBackup] restoreKeyBackup with password: From backup version: ${keysBackupVersion.version}")
 
         cryptoCoroutineScope.launch(coroutineDispatchers.io) {
@@ -859,9 +871,11 @@ internal class DefaultKeysBackupService @Inject constructor(
      * Same method as [RoomKeysRestClient.getRoomKey] except that it accepts nullable
      * parameters and always returns a KeysBackupData object through the Callback.
      */
-    private suspend fun getKeys(sessionId: String?,
-                                roomId: String?,
-                                version: String): KeysBackupData {
+    private suspend fun getKeys(
+            sessionId: String?,
+            roomId: String?,
+            version: String
+    ): KeysBackupData {
         return if (roomId != null && sessionId != null) {
             // Get key for the room and for the session
             val data = getRoomSessionDataTask.execute(GetRoomSessionDataTask.Params(roomId, sessionId, version))
@@ -915,12 +929,12 @@ internal class DefaultKeysBackupService @Inject constructor(
      */
     fun maybeBackupKeys() {
         when {
-            isStucked                              -> {
+            isStuck() -> {
                 // If not already done, or in error case, check for a valid backup version on the homeserver.
                 // If there is one, maybeBackupKeys will be called again.
                 checkAndStartKeysBackup()
             }
-            state == KeysBackupState.ReadyToBackUp -> {
+            getState() == KeysBackupState.ReadyToBackUp -> {
                 keysBackupStateManager.state = KeysBackupState.WillBackUp
 
                 // Wait between 0 and 10 seconds, to avoid backup requests from
@@ -933,14 +947,16 @@ internal class DefaultKeysBackupService @Inject constructor(
                     uiHandler.post { backupKeys() }
                 }
             }
-            else                                   -> {
-                Timber.v("maybeBackupKeys: Skip it because state: $state")
+            else -> {
+                Timber.v("maybeBackupKeys: Skip it because state: ${getState()}")
             }
         }
     }
 
-    override fun getVersion(version: String,
-                            callback: MatrixCallback<KeysVersionResult?>) {
+    override fun getVersion(
+            version: String,
+            callback: MatrixCallback<KeysVersionResult?>
+    ) {
         getKeysBackupVersionTask
                 .configureWith(version) {
                     this.callback = object : MatrixCallback<KeysVersionResult> {
@@ -976,7 +992,7 @@ internal class DefaultKeysBackupService @Inject constructor(
             override fun onSuccess(data: KeysBackupLastVersionResult) {
                 val localBackupVersion = keysBackupVersion?.version
                 when (data) {
-                    KeysBackupLastVersionResult.NoKeysBackup  -> {
+                    KeysBackupLastVersionResult.NoKeysBackup -> {
                         if (localBackupVersion == null) {
                             // No backup on the server, and backup is not active
                             callback.onSuccess(true)
@@ -1018,9 +1034,9 @@ internal class DefaultKeysBackupService @Inject constructor(
     }
 
     override fun checkAndStartKeysBackup() {
-        if (!isStucked) {
+        if (!isStuck()) {
             // Try to start or restart the backup only if it is in unknown or bad state
-            Timber.w("checkAndStartKeysBackup: invalid state: $state")
+            Timber.w("checkAndStartKeysBackup: invalid state: ${getState()}")
 
             return
         }
@@ -1105,6 +1121,7 @@ internal class DefaultKeysBackupService @Inject constructor(
      *
      * @param password the password.
      * @param keysBackupData the backup and its auth data.
+     * @param progressListener listener to track progress
      *
      * @return the recovery key if successful, null in other cases
      */
@@ -1178,10 +1195,12 @@ internal class DefaultKeysBackupService @Inject constructor(
         }
     }
 
-    override fun computePrivateKey(passphrase: String,
-                                   privateKeySalt: String,
-                                   privateKeyIterations: Int,
-                                   progressListener: ProgressListener): ByteArray {
+    override fun computePrivateKey(
+            passphrase: String,
+            privateKeySalt: String,
+            privateKeyIterations: Int,
+            progressListener: ProgressListener
+    ): ByteArray {
         return deriveKey(passphrase, privateKeySalt, privateKeyIterations, progressListener)
     }
 
@@ -1258,16 +1277,16 @@ internal class DefaultKeysBackupService @Inject constructor(
         Timber.v("backupKeys")
 
         // Sanity check, as this method can be called after a delay, the state may have change during the delay
-        if (!isEnabled || backupOlmPkEncryption == null || keysBackupVersion == null) {
+        if (!isEnabled() || backupOlmPkEncryption == null || keysBackupVersion == null) {
             Timber.v("backupKeys: Invalid configuration")
             backupAllGroupSessionsCallback?.onFailure(IllegalStateException("Invalid configuration"))
             resetBackupAllGroupSessionsListeners()
             return
         }
 
-        if (state === KeysBackupState.BackingUp) {
+        if (getState() === KeysBackupState.BackingUp) {
             // Do nothing if we are already backing up
-            Timber.v("backupKeys: Invalid state: $state")
+            Timber.v("backupKeys: Invalid state: ${getState()}")
             return
         }
 
@@ -1359,7 +1378,7 @@ internal class DefaultKeysBackupService @Inject constructor(
                                                     // Do not stay in KeysBackupState.WrongBackUpVersion but check what is available on the homeserver
                                                     checkAndStartKeysBackup()
                                                 }
-                                                else                                  ->
+                                                else ->
                                                     // Come back to the ready state so that we will retry on the next received key
                                                     keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
                                             }
@@ -1481,8 +1500,10 @@ internal class DefaultKeysBackupService @Inject constructor(
         get() = cryptoStore
 
     @VisibleForTesting
-    fun createFakeKeysBackupVersion(keysBackupCreationInfo: MegolmBackupCreationInfo,
-                                    callback: MatrixCallback<KeysVersion>) {
+    fun createFakeKeysBackupVersion(
+            keysBackupCreationInfo: MegolmBackupCreationInfo,
+            callback: MatrixCallback<KeysVersion>
+    ) {
         @Suppress("UNCHECKED_CAST")
         val createKeysBackupVersionBody = CreateKeysBackupVersionBody(
                 algorithm = keysBackupCreationInfo.algorithm,
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 d5bab3318094b6485167893b736f7ea2ad579aaa..8560eb5fc13ba44c77963143727f6e2bce3a70de 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
@@ -44,12 +44,14 @@ internal data class GeneratePrivateKeyResult(
  * Compute a private key from a password.
  *
  * @param password the password to use.
+ * @param progressListener a listener to track progress
  *
  * @return a {privateKey, salt, iterations} tuple.
  */
 @WorkerThread
-internal fun generatePrivateKeyWithPassword(password: String,
-                                            progressListener: ProgressListener?
+internal fun generatePrivateKeyWithPassword(
+        password: String,
+        progressListener: ProgressListener?
 ): GeneratePrivateKeyResult {
     val salt = generateSalt()
     val iterations = DEFAULT_ITERATION
@@ -69,10 +71,12 @@ internal fun generatePrivateKeyWithPassword(password: String,
  * @return a private key.
  */
 @WorkerThread
-internal fun retrievePrivateKeyWithPassword(password: String,
-                                            salt: String,
-                                            iterations: Int,
-                                            progressListener: ProgressListener? = null): ByteArray {
+internal fun retrievePrivateKeyWithPassword(
+        password: String,
+        salt: String,
+        iterations: Int,
+        progressListener: ProgressListener? = null
+): ByteArray {
     return deriveKey(password, salt, iterations, progressListener)
 }
 
@@ -87,10 +91,12 @@ internal fun retrievePrivateKeyWithPassword(password: String,
  * @return a private key.
  */
 @WorkerThread
-internal fun deriveKey(password: String,
-                       salt: String,
-                       iterations: Int,
-                       progressListener: ProgressListener?): ByteArray {
+internal fun deriveKey(
+        password: String,
+        salt: String,
+        iterations: Int,
+        progressListener: ProgressListener?
+): ByteArray {
     // Note: copied and adapted from MXMegolmExportEncryption
     // based on https://en.wikipedia.org/wiki/PBKDF2 algorithm
     // it is simpler than the generic algorithm because the expected key length is equal to the mac key length.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupStateManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupStateManager.kt
index 78ef958bbff0dae1faa5a617c79d8335f16c721c..0614eceb16e51c845e6b38aa328d0baa02544c63 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupStateManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupStateManager.kt
@@ -49,7 +49,7 @@ internal class KeysBackupStateManager(private val uiHandler: Handler) {
                 state == KeysBackupState.BackingUp
 
     // True if unknown or bad state
-    val isStucked: Boolean
+    val isStuck: Boolean
         get() = state == KeysBackupState.Unknown ||
                 state == KeysBackupState.Disabled ||
                 state == KeysBackupState.WrongBackUpVersion ||
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 ea23be59237de603f6c6ce4b649f4b709e3ef22f..48a735018a8dfe3c7cbb931572bd710799ceaf08 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
@@ -60,19 +60,21 @@ internal interface RoomKeysApi {
      * Get information about the given version.
      * If not supported by the server, an error is returned: {"errcode":"M_NOT_FOUND","error":"No backup found"}
      *
-     * @param version  version
+     * @param version version
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/version/{version}")
     suspend fun getKeysBackupVersion(@Path("version") version: String): KeysVersionResult
 
     /**
      * Update information about the given version.
-     * @param version                     version
+     * @param version version
      * @param updateKeysBackupVersionBody the body
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/version/{version}")
-    suspend fun updateKeysBackupVersion(@Path("version") version: String,
-                                        @Body keysBackupVersionBody: UpdateKeysBackupVersionBody)
+    suspend fun updateKeysBackupVersion(
+            @Path("version") version: String,
+            @Body updateKeysBackupVersionBody: UpdateKeysBackupVersionBody
+    )
 
     /* ==========================================================================================
      * Storing keys
@@ -87,38 +89,44 @@ internal interface RoomKeysApi {
      * flag (true is better than false), then by the first_message_index (a lower number is better), and finally by
      * forwarded_count (a lower number is better).
      *
-     * @param roomId        the room id
-     * @param sessionId     the session id
-     * @param version       the version of the backup
+     * @param roomId the room id
+     * @param sessionId the session id
+     * @param version the version of the backup
      * @param keyBackupData the data to send
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys/{roomId}/{sessionId}")
-    suspend fun storeRoomSessionData(@Path("roomId") roomId: String,
-                                     @Path("sessionId") sessionId: String,
-                                     @Query("version") version: String,
-                                     @Body keyBackupData: KeyBackupData): BackupKeysResult
+    suspend fun storeRoomSessionData(
+            @Path("roomId") roomId: String,
+            @Path("sessionId") sessionId: String,
+            @Query("version") version: String,
+            @Body keyBackupData: KeyBackupData
+    ): BackupKeysResult
 
     /**
      * Store several keys for the given room, using the given backup version.
      *
-     * @param roomId             the room id
-     * @param version            the version of the backup
+     * @param roomId the room id
+     * @param version the version of the backup
      * @param roomKeysBackupData the data to send
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys/{roomId}")
-    suspend fun storeRoomSessionsData(@Path("roomId") roomId: String,
-                                      @Query("version") version: String,
-                                      @Body roomKeysBackupData: RoomKeysBackupData): BackupKeysResult
+    suspend fun storeRoomSessionsData(
+            @Path("roomId") roomId: String,
+            @Query("version") version: String,
+            @Body roomKeysBackupData: RoomKeysBackupData
+    ): BackupKeysResult
 
     /**
      * Store several keys, using the given backup version.
      *
-     * @param version        the version of the backup
+     * @param version the version of the backup
      * @param keysBackupData the data to send
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys")
-    suspend fun storeSessionsData(@Query("version") version: String,
-                                  @Body keysBackupData: KeysBackupData): BackupKeysResult
+    suspend fun storeSessionsData(
+            @Query("version") version: String,
+            @Body keysBackupData: KeysBackupData
+    ): BackupKeysResult
 
     /* ==========================================================================================
      * Retrieving keys
@@ -127,29 +135,33 @@ internal interface RoomKeysApi {
     /**
      * Retrieve the key for the given session in the given room from the backup.
      *
-     * @param roomId    the room id
+     * @param roomId the room id
      * @param sessionId the session id
-     * @param version   the version of the backup, or empty String to retrieve the last version
+     * @param version the version of the backup, or empty String to retrieve the last version
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys/{roomId}/{sessionId}")
-    suspend fun getRoomSessionData(@Path("roomId") roomId: String,
-                                   @Path("sessionId") sessionId: String,
-                                   @Query("version") version: String): KeyBackupData
+    suspend fun getRoomSessionData(
+            @Path("roomId") roomId: String,
+            @Path("sessionId") sessionId: String,
+            @Query("version") version: String
+    ): KeyBackupData
 
     /**
      * Retrieve all the keys for the given room from the backup.
      *
-     * @param roomId   the room id
-     * @param version  the version of the backup, or empty String to retrieve the last version
+     * @param roomId the room id
+     * @param version the version of the backup, or empty String to retrieve the last version
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys/{roomId}")
-    suspend fun getRoomSessionsData(@Path("roomId") roomId: String,
-                                    @Query("version") version: String): RoomKeysBackupData
+    suspend fun getRoomSessionsData(
+            @Path("roomId") roomId: String,
+            @Query("version") version: String
+    ): RoomKeysBackupData
 
     /**
      * Retrieve all the keys from the backup.
      *
-     * @param version  the version of the backup, or empty String to retrieve the last version
+     * @param version the version of the backup, or empty String to retrieve the last version
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys")
     suspend fun getSessionsData(@Query("version") version: String): KeysBackupData
@@ -162,16 +174,20 @@ internal interface RoomKeysApi {
      * Deletes keys from the backup.
      */
     @DELETE(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys/{roomId}/{sessionId}")
-    suspend fun deleteRoomSessionData(@Path("roomId") roomId: String,
-                                      @Path("sessionId") sessionId: String,
-                                      @Query("version") version: String)
+    suspend fun deleteRoomSessionData(
+            @Path("roomId") roomId: String,
+            @Path("sessionId") sessionId: String,
+            @Query("version") version: String
+    )
 
     /**
      * Deletes keys from the backup.
      */
     @DELETE(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys/{roomId}")
-    suspend fun deleteRoomSessionsData(@Path("roomId") roomId: String,
-                                       @Query("version") version: String)
+    suspend fun deleteRoomSessionsData(
+            @Path("roomId") roomId: String,
+            @Query("version") version: String
+    )
 
     /**
      * Deletes keys from the backup.
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 6bfa56ae8df7cfec01d60f6b474c091314f6fdd8..6b747d19f2f8defb35ea18c911e7afbe568bf9fb 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
@@ -59,7 +59,7 @@ internal data class MXKey(
     /**
      * Returns a signature for an user Id and a signkey.
      *
-     * @param userId  the user id
+     * @param userId the user id
      * @param signkey the sign key
      * @return the signature
      */
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 9fdeda01c9db3093be37c53f78eae27458df7711..85ba1762d3bd62c3bfd899204103f8dea4fb2950 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
@@ -69,12 +69,14 @@ internal data class KeyVerificationAccept(
     override fun toSendToDeviceObject() = this
 
     companion object : VerificationInfoAcceptFactory {
-        override fun create(tid: String,
-                            keyAgreementProtocol: String,
-                            hash: String,
-                            commitment: String,
-                            messageAuthenticationCode: String,
-                            shortAuthenticationStrings: List<String>): VerificationInfoAccept {
+        override fun create(
+                tid: String,
+                keyAgreementProtocol: String,
+                hash: String,
+                commitment: String,
+                messageAuthenticationCode: String,
+                shortAuthenticationStrings: List<String>
+        ): VerificationInfoAccept {
             return KeyVerificationAccept(
                     transactionId = tid,
                     keyAgreementProtocol = keyAgreementProtocol,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/VerificationMethodValues.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/VerificationMethodValues.kt
index c07434f5861a745b4a3554fb266443764efafd54..afe6191bf7fa55f55e67283d36ea20ab0f00916f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/VerificationMethodValues.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/VerificationMethodValues.kt
@@ -28,7 +28,7 @@ internal const val VERIFICATION_METHOD_RECIPROCATE = "m.reciprocate.v1"
 
 internal fun VerificationMethod.toValue(): String {
     return when (this) {
-        VerificationMethod.SAS          -> VERIFICATION_METHOD_SAS
+        VerificationMethod.SAS -> VERIFICATION_METHOD_SAS
         VerificationMethod.QR_CODE_SCAN -> VERIFICATION_METHOD_QR_CODE_SCAN
         VerificationMethod.QR_CODE_SHOW -> VERIFICATION_METHOD_QR_CODE_SHOW
     }
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 1ded9c6c7e32b83f11870cd6cca18470746ec0ee..ddb048a912a87ed70c102faff312838f884915a6 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
@@ -30,6 +30,7 @@ import org.matrix.android.sdk.api.session.securestorage.EncryptedSecretContent
 import org.matrix.android.sdk.api.session.securestorage.IntegrityResult
 import org.matrix.android.sdk.api.session.securestorage.KeyInfo
 import org.matrix.android.sdk.api.session.securestorage.KeyInfoResult
+import org.matrix.android.sdk.api.session.securestorage.KeyRef
 import org.matrix.android.sdk.api.session.securestorage.KeySigner
 import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
 import org.matrix.android.sdk.api.session.securestorage.SecretStorageKeyContent
@@ -62,10 +63,12 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
         private val cryptoCoroutineScope: CoroutineScope
 ) : SharedSecretStorageService {
 
-    override suspend fun generateKey(keyId: String,
-                                     key: SsssKeySpec?,
-                                     keyName: String,
-                                     keySigner: KeySigner?): SsssKeyCreationInfo {
+    override suspend fun generateKey(
+            keyId: String,
+            key: SsssKeySpec?,
+            keyName: String,
+            keySigner: KeySigner?
+    ): SsssKeyCreationInfo {
         return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
             val bytes = (key as? RawBytesKeySpec)?.privateKey
                     ?: ByteArray(32).also {
@@ -94,11 +97,13 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
         }
     }
 
-    override suspend fun generateKeyWithPassphrase(keyId: String,
-                                                   keyName: String,
-                                                   passphrase: String,
-                                                   keySigner: KeySigner,
-                                                   progressListener: ProgressListener?): SsssKeyCreationInfo {
+    override suspend fun generateKeyWithPassphrase(
+            keyId: String,
+            keyName: String,
+            passphrase: String,
+            keySigner: KeySigner,
+            progressListener: ProgressListener?
+    ): SsssKeyCreationInfo {
         return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
             val privatePart = generatePrivateKeyWithPassword(passphrase, progressListener)
 
@@ -157,7 +162,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
         return getKey(keyId)
     }
 
-    override suspend fun storeSecret(name: String, secretBase64: String, keys: List<SharedSecretStorageService.KeyRef>) {
+    override suspend fun storeSecret(name: String, secretBase64: String, keys: List<KeyRef>) {
         withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) {
             val encryptedContents = HashMap<String, EncryptedSecretContent>()
             keys.forEach {
@@ -174,7 +179,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
                             throw SharedSecretStorageError.UnknownAlgorithm(key.keyInfo.content.algorithm ?: "")
                         }
                     }
-                    is KeyInfoResult.Error   -> throw key.error
+                    is KeyInfoResult.Error -> throw key.error
                 }
             }
 
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 480009dbce0c45c56a29916eba6229df1abbbc68..b18de34329452f229e429a1027dd257939440bf3 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
@@ -164,16 +164,14 @@ internal interface IMXCryptoStore {
 
     /**
      * Store the end to end account for the logged-in user.
-     *
-     * @param account the account to save
      */
     fun saveOlmAccount()
 
     /**
      * Retrieve a device for a user.
      *
+     * @param userId the user's id.
      * @param deviceId the device id.
-     * @param userId   the user's id.
      * @return the device
      */
     fun getUserDevice(userId: String, deviceId: String): CryptoDeviceInfo?
@@ -189,15 +187,17 @@ internal interface IMXCryptoStore {
     /**
      * Store the known devices for a user.
      *
-     * @param userId  The user's id.
+     * @param userId The user's id.
      * @param devices A map from device id to 'MXDevice' object for the device.
      */
     fun storeUserDevices(userId: String, devices: Map<String, CryptoDeviceInfo>?)
 
-    fun storeUserCrossSigningKeys(userId: String,
-                                  masterKey: CryptoCrossSigningKey?,
-                                  selfSigningKey: CryptoCrossSigningKey?,
-                                  userSigningKey: CryptoCrossSigningKey?)
+    fun storeUserCrossSigningKeys(
+            userId: String,
+            masterKey: CryptoCrossSigningKey?,
+            selfSigningKey: CryptoCrossSigningKey?,
+            userSigningKey: CryptoCrossSigningKey?
+    )
 
     /**
      * Retrieve the known devices for a user.
@@ -225,7 +225,7 @@ internal interface IMXCryptoStore {
     /**
      * Store the crypto algorithm for a room.
      *
-     * @param roomId    the id of the room.
+     * @param roomId the id of the room.
      * @param algorithm the algorithm.
      */
     fun storeRoomAlgorithm(roomId: String, algorithm: String?)
@@ -253,7 +253,7 @@ internal interface IMXCryptoStore {
     /**
      * Store a session between the logged-in user and another device.
      *
-     * @param olmSessionWrapper   the end-to-end session.
+     * @param olmSessionWrapper the end-to-end session.
      * @param deviceKey the public key of the other device.
      */
     fun storeSession(olmSessionWrapper: OlmSessionWrapper, deviceKey: String)
@@ -331,7 +331,7 @@ internal interface IMXCryptoStore {
     /**
      * Mark inbound group sessions as backed up on the user homeserver.
      *
-     * @param sessions the sessions
+     * @param olmInboundGroupSessionWrappers the sessions
      */
     fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List<OlmInboundGroupSessionWrapper2>)
 
@@ -361,7 +361,7 @@ internal interface IMXCryptoStore {
     /**
      * Get the tracking status of a specified userId devices.
      *
-     * @param userId       the user id
+     * @param userId the user id
      * @param defaultValue the default value
      * @return the tracking status
      */
@@ -380,7 +380,9 @@ internal interface IMXCryptoStore {
     /**
      * Look for an existing outgoing room key request, and if none is found, add a new one.
      *
-     * @param request the request
+     * @param requestBody the request
+     * @param recipients list of recipients
+     * @param fromIndex start index
      * @return either the same instance as passed in, or the existing one.
      */
     fun getOrAddOutgoingRoomKeyRequest(requestBody: RoomKeyRequestBody, recipients: Map<String, List<String>>, fromIndex: Int): OutgoingKeyRequest
@@ -392,7 +394,8 @@ internal interface IMXCryptoStore {
             algorithm: String,
             senderKey: String,
             fromDevice: String?,
-            event: Event)
+            event: Event
+    )
 
     fun deleteOutgoingRoomKeyRequest(requestId: String)
     fun deleteOutgoingRoomKeyRequestInState(state: OutgoingRoomKeyRequestState)
@@ -479,8 +482,14 @@ internal interface IMXCryptoStore {
     fun addWithHeldMegolmSession(withHeldContent: RoomKeyWithHeldContent)
     fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent?
 
-    fun markedSessionAsShared(roomId: String?, sessionId: String, userId: String, deviceId: String,
-                              deviceIdentityKey: String, chainIndex: Int)
+    fun markedSessionAsShared(
+            roomId: String?,
+            sessionId: String,
+            userId: String,
+            deviceId: String,
+            deviceIdentityKey: String,
+            chainIndex: Int
+    )
 
     /**
      * Query for information on this session sharing history.
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 533ab70bba3ce0095825a10deae8f83d7df07d06..c56e4d320b82ec41cb6a9fb22f42ba9c9c0aaccd 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
@@ -322,10 +322,12 @@ internal class RealmCryptoStore @Inject constructor(
         }
     }
 
-    override fun storeUserCrossSigningKeys(userId: String,
-                                           masterKey: CryptoCrossSigningKey?,
-                                           selfSigningKey: CryptoCrossSigningKey?,
-                                           userSigningKey: CryptoCrossSigningKey?) {
+    override fun storeUserCrossSigningKeys(
+            userId: String,
+            masterKey: CryptoCrossSigningKey?,
+            selfSigningKey: CryptoCrossSigningKey?,
+            userSigningKey: CryptoCrossSigningKey?
+    ) {
         doRealmTransaction(realmConfiguration) { realm ->
             UserEntity.getOrCreate(realm, userId)
                     .let { userEntity ->
@@ -1154,9 +1156,11 @@ internal class RealmCryptoStore @Inject constructor(
         }
     }
 
-    override fun getOrAddOutgoingRoomKeyRequest(requestBody: RoomKeyRequestBody,
-                                                recipients: Map<String, List<String>>,
-                                                fromIndex: Int): OutgoingKeyRequest {
+    override fun getOrAddOutgoingRoomKeyRequest(
+            requestBody: RoomKeyRequestBody,
+            recipients: Map<String, List<String>>,
+            fromIndex: Int
+    ): OutgoingKeyRequest {
         // Insert the request and return the one passed in parameter
         lateinit var request: OutgoingKeyRequest
         doRealmTransaction(realmConfiguration) { realm ->
@@ -1220,12 +1224,14 @@ internal class RealmCryptoStore @Inject constructor(
         }
     }
 
-    override fun updateOutgoingRoomKeyReply(roomId: String,
-                                            sessionId: String,
-                                            algorithm: String,
-                                            senderKey: String,
-                                            fromDevice: String?,
-                                            event: Event) {
+    override fun updateOutgoingRoomKeyReply(
+            roomId: String,
+            sessionId: String,
+            algorithm: String,
+            senderKey: String,
+            fromDevice: String?,
+            event: Event
+    ) {
         doRealmTransaction(realmConfiguration) { realm ->
             realm.where<OutgoingKeyRequestEntity>()
                     .equalTo(OutgoingKeyRequestEntityFields.ROOM_ID, roomId)
@@ -1266,7 +1272,8 @@ internal class RealmCryptoStore @Inject constructor(
             senderKey: String,
             algorithm: String,
             fromUser: String,
-            fromDevice: String) {
+            fromDevice: String
+    ) {
         monarchy.writeAsync { realm ->
             val now = clock.epochMillis()
             realm.createObject<AuditTrailEntity>().apply {
@@ -1288,13 +1295,15 @@ internal class RealmCryptoStore @Inject constructor(
         }
     }
 
-    override fun saveWithheldAuditTrail(roomId: String,
-                                        sessionId: String,
-                                        senderKey: String,
-                                        algorithm: String,
-                                        code: WithHeldCode,
-                                        userId: String,
-                                        deviceId: String) {
+    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 {
@@ -1316,34 +1325,39 @@ internal class RealmCryptoStore @Inject constructor(
         }
     }
 
-    override fun saveForwardKeyAuditTrail(roomId: String,
-                                          sessionId: String,
-                                          senderKey: String,
-                                          algorithm: String,
-                                          userId: String,
-                                          deviceId: String,
-                                          chainIndex: Long?) {
+    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?) {
+    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
+    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()
@@ -1617,12 +1631,14 @@ internal class RealmCryptoStore @Inject constructor(
         }
     }
 
-    override fun markedSessionAsShared(roomId: String?,
-                                       sessionId: String,
-                                       userId: String,
-                                       deviceId: String,
-                                       deviceIdentityKey: String,
-                                       chainIndex: Int) {
+    override fun markedSessionAsShared(
+            roomId: String?,
+            sessionId: String,
+            userId: String,
+            deviceId: String,
+            deviceIdentityKey: String,
+            chainIndex: Int
+    ) {
         doRealmTransaction(realmConfiguration) { realm ->
             SharedSessionEntity.create(
                     realm = realm,
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 e5bdd2aa9b7c436396832b9d412e1374ca1d7199..0a986892d98a4182ab16d6a15620c3a7f04a08a0 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
@@ -104,10 +104,10 @@ internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4)
 
                             val trustLevel = realm.createObject("TrustLevelEntity")
                             when (oldDevice.verified) {
-                                MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN    -> {
+                                MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> {
                                     obj.setNull(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`)
                                 }
-                                MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED    -> {
+                                MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> {
                                     trustLevel.setNull(TrustLevelEntityFields.LOCALLY_VERIFIED)
                                     trustLevel.setNull(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED)
                                     obj.setBoolean(DeviceInfoEntityFields.IS_BLOCKED, oldDevice.isBlocked)
@@ -118,7 +118,7 @@ internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4)
                                     trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false)
                                     obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
                                 }
-                                MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED   -> {
+                                MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> {
                                     trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, true)
                                     trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false)
                                     obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel)
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
index 80ae4a8d0d39ec3c79f8dc99cb51b19b303670d8..fe8e9f1db731c42fb7a4752aed291591319147f0 100644
--- 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
@@ -30,7 +30,7 @@ internal object AuditTrailMapper {
     fun map(entity: AuditTrailEntity): AuditTrail? {
         val contentJson = entity.contentJson ?: return null
         return when (entity.type) {
-            TrailType.OutgoingKeyForward.name  -> {
+            TrailType.OutgoingKeyForward.name -> {
                 val info = tryOrNull {
                     MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).fromJson(contentJson)
                 } ?: return null
@@ -50,7 +50,7 @@ internal object AuditTrailMapper {
                         info = info
                 )
             }
-            TrailType.IncomingKeyRequest.name  -> {
+            TrailType.IncomingKeyRequest.name -> {
                 val info = tryOrNull {
                     MoshiProvider.providesMoshi().adapter(IncomingKeyRequestInfo::class.java).fromJson(contentJson)
                 } ?: return null
@@ -60,7 +60,7 @@ internal object AuditTrailMapper {
                         info = info
                 )
             }
-            TrailType.IncomingKeyForward.name  -> {
+            TrailType.IncomingKeyForward.name -> {
                 val info = tryOrNull {
                     MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).fromJson(contentJson)
                 } ?: return null
@@ -70,7 +70,7 @@ internal object AuditTrailMapper {
                         info = info
                 )
             }
-            else                               -> {
+            else -> {
                 AuditTrail(
                         ageLocalTs = entity.ageLocalTs ?: 0,
                         type = TrailType.Unknown,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt
index 83671b28d95e387ba48f2b2b9211a4a47c4d5e7d..a4f6c279acb964fd1697847a0edc7c9f3b545831 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt
@@ -33,7 +33,8 @@ internal open class OlmInboundGroupSessionEntity(
         // olmInboundGroupSessionData contains Json
         var olmInboundGroupSessionData: String? = null,
         // Indicate if the key has been backed up to the homeserver
-        var backedUp: Boolean = false) :
+        var backedUp: Boolean = false
+) :
         RealmObject() {
 
     fun getInboundGroupSession(): OlmInboundGroupSessionWrapper2? {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmSessionEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmSessionEntity.kt
index 1a637d76c4ac8c9dc81fd1e924d4ee4196a39e45..9f010db288ea63437130b0eed147bc941d1dbf8f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmSessionEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmSessionEntity.kt
@@ -25,11 +25,13 @@ import org.matrix.olm.OlmSession
 internal fun OlmSessionEntity.Companion.createPrimaryKey(sessionId: String, deviceKey: String) = "$sessionId|$deviceKey"
 
 // olmSessionData is a serialized OlmSession
-internal open class OlmSessionEntity(@PrimaryKey var primaryKey: String = "",
-                                     var sessionId: String? = null,
-                                     var deviceKey: String? = null,
-                                     var olmSessionData: String? = null,
-                                     var lastReceivedMessageTs: Long = 0) :
+internal open class OlmSessionEntity(
+        @PrimaryKey var primaryKey: String = "",
+        var sessionId: String? = null,
+        var deviceKey: String? = null,
+        var olmSessionData: String? = null,
+        var lastReceivedMessageTs: Long = 0
+) :
         RealmObject() {
 
     fun getOlmSession(): OlmSession? {
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
index 7a8ba188093879501e5033e7066debdc34f7f6f1..854d148b76c66be956c91c95de583bcacd83f6c9 100644
--- 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
@@ -117,7 +117,7 @@ internal open class OutgoingKeyRequestEntity(
 
     private fun eventToResult(event: Event): RequestResult? {
         return when (event.getClearType()) {
-            EventType.ROOM_KEY_WITHHELD  -> {
+            EventType.ROOM_KEY_WITHHELD -> {
                 event.content.toModel<RoomKeyWithHeldContent>()?.code?.let {
                     RequestResult.Failure(it)
                 }
@@ -125,7 +125,7 @@ internal open class OutgoingKeyRequestEntity(
             EventType.FORWARDED_ROOM_KEY -> {
                 RequestResult.Success((event.content?.get("chain_index") as? Number)?.toInt() ?: 0)
             }
-            else                         -> null
+            else -> null
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/SharedSessionQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/SharedSessionQueries.kt
index 8bf9794375fb0be360695b1577daf4432c6d958b..85dd50c88ed35605a9284356b716d13a33354029 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/SharedSessionQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/SharedSessionQueries.kt
@@ -24,12 +24,14 @@ import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
 import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntity
 import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields
 
-internal fun SharedSessionEntity.Companion.get(realm: Realm,
-                                               roomId: String?,
-                                               sessionId: String,
-                                               userId: String,
-                                               deviceId: String,
-                                               deviceIdentityKey: String?): SharedSessionEntity? {
+internal fun SharedSessionEntity.Companion.get(
+        realm: Realm,
+        roomId: String?,
+        sessionId: String,
+        userId: String,
+        deviceId: String,
+        deviceIdentityKey: String?
+): SharedSessionEntity? {
     return realm.where<SharedSessionEntity>()
             .equalTo(SharedSessionEntityFields.ROOM_ID, roomId)
             .equalTo(SharedSessionEntityFields.SESSION_ID, sessionId)
@@ -48,12 +50,15 @@ internal fun SharedSessionEntity.Companion.get(realm: Realm, roomId: String?, se
             .findAll()
 }
 
-internal fun SharedSessionEntity.Companion.create(realm: Realm, roomId: String?,
-                                                  sessionId: String,
-                                                  userId: String,
-                                                  deviceId: String,
-                                                  deviceIdentityKey: String,
-                                                  chainIndex: Int): SharedSessionEntity {
+internal fun SharedSessionEntity.Companion.create(
+        realm: Realm,
+        roomId: String?,
+        sessionId: String,
+        userId: String,
+        deviceId: String,
+        deviceIdentityKey: String,
+        chainIndex: Int
+): SharedSessionEntity {
     return realm.createObject<SharedSessionEntity>().apply {
         this.roomId = roomId
         this.algorithm = MXCRYPTO_ALGORITHM_MEGOLM
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 394c6189681ca919ebc27e78efd6fa6e6e6f2096..a4b4cd0761bca993a558e8c857644f64e4be6a8e 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
@@ -31,10 +31,11 @@ import org.matrix.android.sdk.internal.task.Task
 import javax.inject.Inject
 
 internal interface EncryptEventTask : Task<EncryptEventTask.Params, Event> {
-    data class Params(val roomId: String,
-                      val event: Event,
-                      /**Do not encrypt these keys, keep them as is in encrypted content (e.g. m.relates_to)*/
-                      val keepKeys: List<String>? = null
+    data class Params(
+            val roomId: String,
+            val event: Event,
+            /**Do not encrypt these keys, keep them as is in encrypted content (e.g. m.relates_to)*/
+            val keepKeys: List<String>? = null
     )
 }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt
index d6a7f3c6a026c44d942911446a38fd2064341e72..56bdc8cae88495ac3ca855c2656e206b873fbd53 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt
@@ -32,7 +32,8 @@ internal interface RedactEventTask : Task<RedactEventTask.Params, String> {
 
 internal class DefaultRedactEventTask @Inject constructor(
         private val roomAPI: RoomAPI,
-        private val globalErrorReceiver: GlobalErrorReceiver) : RedactEventTask {
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : RedactEventTask {
 
     override suspend fun execute(params: RedactEventTask.Params): String {
         val response = executeRequest(globalErrorReceiver) {
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 50efe51bc1bb1502d58f7156f863f6bbb46c56ac..fbd9d245d9c1493b29b5f76d357f0e5e27b69ac3 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
@@ -39,7 +39,8 @@ internal class DefaultSendEventTask @Inject constructor(
         private val encryptEventTask: EncryptEventTask,
         private val loadRoomMembersTask: LoadRoomMembersTask,
         private val roomAPI: RoomAPI,
-        private val globalErrorReceiver: GlobalErrorReceiver) : SendEventTask {
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : SendEventTask {
 
     override suspend fun execute(params: SendEventTask.Params): String {
         try {
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 7c52c62d92f218ebb593b577aee2724da54ba319..944f41d488b86eacaf103b823dea68eb4244fc6f 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
@@ -37,7 +37,8 @@ internal class DefaultSendVerificationMessageTask @Inject constructor(
         private val encryptEventTask: EncryptEventTask,
         private val roomAPI: RoomAPI,
         private val cryptoSessionInfoProvider: CryptoSessionInfoProvider,
-        private val globalErrorReceiver: GlobalErrorReceiver) : SendVerificationMessageTask {
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : SendVerificationMessageTask {
 
     override suspend fun execute(params: SendVerificationMessageTask.Params): String {
         val event = handleEncryption(params)
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 4ab7e0e30c7bc589a052ddaeb756ab2becd90d40..04fb6c4858878eb943cbd8b6e3ff8170e2d33e8a 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
@@ -35,7 +35,7 @@ internal object HkdfSha256 {
     /**
      * HkdfSha256-Extract(salt, IKM) -> PRK.
      *
-     * @param salt  optional salt value (a non-secret random value);
+     * @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.
      * @param ikm input keying material
      */
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 a9d5cf1191d2dce87dd12969b4c066d5b5b2cf15..6b3bb1e641472acb8e1399e5ac70a07eb8724df2 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
@@ -60,26 +60,26 @@ internal class DefaultIncomingSASDefaultVerificationTransaction(
     override val uxState: IncomingSasVerificationTransaction.UxState
         get() {
             return when (val immutableState = state) {
-                is VerificationTxState.OnStarted      -> IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT
+                is VerificationTxState.OnStarted -> IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT
                 is VerificationTxState.SendingAccept,
                 is VerificationTxState.Accepted,
                 is VerificationTxState.OnKeyReceived,
                 is VerificationTxState.SendingKey,
-                is VerificationTxState.KeySent        -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
+                is VerificationTxState.KeySent -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
                 is VerificationTxState.ShortCodeReady -> IncomingSasVerificationTransaction.UxState.SHOW_SAS
                 is VerificationTxState.ShortCodeAccepted,
                 is VerificationTxState.SendingMac,
                 is VerificationTxState.MacSent,
-                is VerificationTxState.Verifying      -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
-                is VerificationTxState.Verified       -> IncomingSasVerificationTransaction.UxState.VERIFIED
-                is VerificationTxState.Cancelled      -> {
+                is VerificationTxState.Verifying -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
+                is VerificationTxState.Verified -> IncomingSasVerificationTransaction.UxState.VERIFIED
+                is VerificationTxState.Cancelled -> {
                     if (immutableState.byMe) {
                         IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME
                     } else {
                         IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER
                     }
                 }
-                else                                  -> IncomingSasVerificationTransaction.UxState.UNKNOWN
+                else -> IncomingSasVerificationTransaction.UxState.UNKNOWN
             }
         }
 
@@ -232,7 +232,7 @@ internal class DefaultIncomingSASDefaultVerificationTransaction(
                 val sasInfo = "MATRIX_KEY_VERIFICATION_SAS|$otherUserId|$otherDeviceId|$otherKey|$userId|$deviceId|${getSAS().publicKey}|$transactionId"
                 return getSAS().generateShortCode(sasInfo, 6)
             }
-            else             -> {
+            else -> {
                 // Protocol has been checked earlier
                 throw IllegalArgumentException()
             }
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 ddb8ed232ba1bdc865cbfa313aa3f80d09e269d8..f1cf1b7547c566b211369a5db361d2481986b4f0 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
@@ -57,27 +57,27 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction(
     override val uxState: OutgoingSasVerificationTransaction.UxState
         get() {
             return when (val immutableState = state) {
-                is VerificationTxState.None           -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_START
+                is VerificationTxState.None -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_START
                 is VerificationTxState.SendingStart,
                 is VerificationTxState.Started,
                 is VerificationTxState.OnAccepted,
                 is VerificationTxState.SendingKey,
                 is VerificationTxState.KeySent,
-                is VerificationTxState.OnKeyReceived  -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
+                is VerificationTxState.OnKeyReceived -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT
                 is VerificationTxState.ShortCodeReady -> OutgoingSasVerificationTransaction.UxState.SHOW_SAS
                 is VerificationTxState.ShortCodeAccepted,
                 is VerificationTxState.SendingMac,
                 is VerificationTxState.MacSent,
-                is VerificationTxState.Verifying      -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
-                is VerificationTxState.Verified       -> OutgoingSasVerificationTransaction.UxState.VERIFIED
-                is VerificationTxState.Cancelled      -> {
+                is VerificationTxState.Verifying -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION
+                is VerificationTxState.Verified -> OutgoingSasVerificationTransaction.UxState.VERIFIED
+                is VerificationTxState.Cancelled -> {
                     if (immutableState.byMe) {
                         OutgoingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER
                     } else {
                         OutgoingSasVerificationTransaction.UxState.CANCELLED_BY_ME
                     }
                 }
-                else                                  -> OutgoingSasVerificationTransaction.UxState.UNKNOWN
+                else -> OutgoingSasVerificationTransaction.UxState.UNKNOWN
             }
         }
 
@@ -224,7 +224,7 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction(
                 val sasInfo = "MATRIX_KEY_VERIFICATION_SAS|$userId|$deviceId|${getSAS().publicKey}|$otherUserId|$otherDeviceId|$otherKey|$transactionId"
                 return getSAS().generateShortCode(sasInfo, 6)
             }
-            else             -> {
+            else -> {
                 // Protocol has been checked earlier
                 throw IllegalArgumentException()
             }
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 6da674d6e4aa1ca996e7b5a1134ded5e686a1a7a..1a04ee030249fabee11171d0f1607a11091052ba 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
@@ -129,31 +129,31 @@ internal class DefaultVerificationService @Inject constructor(
         Timber.d("## SAS onToDeviceEvent ${event.getClearType()}")
         cryptoCoroutineScope.launch(coroutineDispatchers.dmVerif) {
             when (event.getClearType()) {
-                EventType.KEY_VERIFICATION_START         -> {
+                EventType.KEY_VERIFICATION_START -> {
                     onStartRequestReceived(event)
                 }
-                EventType.KEY_VERIFICATION_CANCEL        -> {
+                EventType.KEY_VERIFICATION_CANCEL -> {
                     onCancelReceived(event)
                 }
-                EventType.KEY_VERIFICATION_ACCEPT        -> {
+                EventType.KEY_VERIFICATION_ACCEPT -> {
                     onAcceptReceived(event)
                 }
-                EventType.KEY_VERIFICATION_KEY           -> {
+                EventType.KEY_VERIFICATION_KEY -> {
                     onKeyReceived(event)
                 }
-                EventType.KEY_VERIFICATION_MAC           -> {
+                EventType.KEY_VERIFICATION_MAC -> {
                     onMacReceived(event)
                 }
-                EventType.KEY_VERIFICATION_READY         -> {
+                EventType.KEY_VERIFICATION_READY -> {
                     onReadyReceived(event)
                 }
-                EventType.KEY_VERIFICATION_DONE          -> {
+                EventType.KEY_VERIFICATION_DONE -> {
                     onDoneReceived(event)
                 }
                 MessageType.MSGTYPE_VERIFICATION_REQUEST -> {
                     onRequestReceived(event)
                 }
-                else                                     -> {
+                else -> {
                     // ignore
                 }
             }
@@ -163,7 +163,7 @@ internal class DefaultVerificationService @Inject constructor(
     fun onRoomEvent(event: Event) {
         cryptoCoroutineScope.launch(coroutineDispatchers.dmVerif) {
             when (event.getClearType()) {
-                EventType.KEY_VERIFICATION_START  -> {
+                EventType.KEY_VERIFICATION_START -> {
                     onRoomStartRequestReceived(event)
                 }
                 EventType.KEY_VERIFICATION_CANCEL -> {
@@ -173,24 +173,24 @@ internal class DefaultVerificationService @Inject constructor(
                 EventType.KEY_VERIFICATION_ACCEPT -> {
                     onRoomAcceptReceived(event)
                 }
-                EventType.KEY_VERIFICATION_KEY    -> {
+                EventType.KEY_VERIFICATION_KEY -> {
                     onRoomKeyRequestReceived(event)
                 }
-                EventType.KEY_VERIFICATION_MAC    -> {
+                EventType.KEY_VERIFICATION_MAC -> {
                     onRoomMacReceived(event)
                 }
-                EventType.KEY_VERIFICATION_READY  -> {
+                EventType.KEY_VERIFICATION_READY -> {
                     onRoomReadyReceived(event)
                 }
-                EventType.KEY_VERIFICATION_DONE   -> {
+                EventType.KEY_VERIFICATION_DONE -> {
                     onRoomDoneReceived(event)
                 }
-                EventType.MESSAGE                 -> {
+                EventType.MESSAGE -> {
                     if (MessageType.MSGTYPE_VERIFICATION_REQUEST == event.getClearContent().toModel<MessageContent>()?.msgType) {
                         onRoomRequestReceived(event)
                     }
                 }
-                else                              -> {
+                else -> {
                     // ignore
                 }
             }
@@ -472,9 +472,11 @@ internal class DefaultVerificationService @Inject constructor(
     /**
      * Return a CancelCode to make the caller cancel the verification. Else return null
      */
-    private suspend fun handleStart(otherUserId: String?,
-                                    startReq: ValidVerificationInfoStart,
-                                    txConfigure: (DefaultVerificationTransaction) -> Unit): CancelCode? {
+    private suspend fun handleStart(
+            otherUserId: String?,
+            startReq: ValidVerificationInfoStart,
+            txConfigure: (DefaultVerificationTransaction) -> Unit
+    ): CancelCode? {
         Timber.d("## SAS onStartRequestReceived $startReq")
         if (otherUserId?.let { checkKeysAreDownloaded(it, startReq.fromDevice) } != null) {
             val tid = startReq.transactionId
@@ -505,9 +507,9 @@ internal class DefaultVerificationService @Inject constructor(
             }
 
             when (startReq) {
-                is ValidVerificationInfoStart.SasVerificationInfoStart         -> {
+                is ValidVerificationInfoStart.SasVerificationInfoStart -> {
                     when (existing) {
-                        is SasVerificationTransaction    -> {
+                        is SasVerificationTransaction -> {
                             // should cancel both!
                             Timber.v("## SAS onStartRequestReceived - Request exist with same id ${startReq.transactionId}")
                             existing.cancel(CancelCode.UnexpectedMessage)
@@ -517,7 +519,7 @@ internal class DefaultVerificationService @Inject constructor(
                         is QrCodeVerificationTransaction -> {
                             // Nothing to do?
                         }
-                        null                             -> {
+                        null -> {
                             getExistingTransactionsForUser(otherUserId)
                                     ?.filterIsInstance(SasVerificationTransaction::class.java)
                                     ?.takeIf { it.isNotEmpty() }
@@ -589,8 +591,10 @@ internal class DefaultVerificationService @Inject constructor(
     }
 
     // TODO Refacto: It could just return a boolean
-    private suspend fun checkKeysAreDownloaded(otherUserId: String,
-                                               otherDeviceId: String): MXUsersDevicesMap<CryptoDeviceInfo>? {
+    private suspend fun checkKeysAreDownloaded(
+            otherUserId: String,
+            otherDeviceId: String
+    ): MXUsersDevicesMap<CryptoDeviceInfo>? {
         return try {
             var keys = deviceListManager.downloadKeys(listOf(otherUserId), false)
             if (keys.getUserDeviceIds(otherUserId)?.contains(otherDeviceId) == true) {
@@ -899,9 +903,11 @@ internal class DefaultVerificationService @Inject constructor(
         }
     }
 
-    private fun handleReadyReceived(senderId: String,
-                                    readyReq: ValidVerificationInfoReady,
-                                    transportCreator: (DefaultVerificationTransaction) -> VerificationTransport) {
+    private fun handleReadyReceived(
+            senderId: String,
+            readyReq: ValidVerificationInfoReady,
+            transportCreator: (DefaultVerificationTransaction) -> VerificationTransport
+    ) {
         val existingRequest = getExistingVerificationRequests(senderId).find { it.transactionId == readyReq.transactionId }
         if (existingRequest == null) {
             Timber.e("## SAS Received Ready for unknown request txId:${readyReq.transactionId} fromDevice ${readyReq.fromDevice}")
@@ -942,6 +948,22 @@ internal class DefaultVerificationService @Inject constructor(
                         readyInfo = readyReq
                 )
         )
+
+        notifyOthersOfAcceptance(readyReq.transactionId, readyReq.fromDevice)
+    }
+
+    /**
+     * Gets a list of device ids excluding the current one.
+     */
+    private fun getMyOtherDeviceIds(): List<String> = cryptoStore.getUserDevices(userId)?.keys?.filter { it != deviceId }.orEmpty()
+
+    /**
+     * Notifies other devices that the current verification transaction is being handled by [acceptedByDeviceId].
+     */
+    private fun notifyOthersOfAcceptance(transactionId: String, acceptedByDeviceId: String) {
+        val deviceIds = getMyOtherDeviceIds().filter { it != acceptedByDeviceId }
+        val transport = verificationTransportToDeviceFactory.createTransport(null)
+        transport.cancelTransaction(transactionId, userId, deviceIds, CancelCode.AcceptedByAnotherDevice)
     }
 
     private fun createQrCodeData(requestId: String?, otherUserId: String, otherDeviceId: String?): QrCodeData? {
@@ -951,12 +973,12 @@ internal class DefaultVerificationService @Inject constructor(
         }
 
         return when {
-            userId != otherUserId                        ->
+            userId != otherUserId ->
                 createQrCodeDataForDistinctUser(requestId, otherUserId)
             crossSigningService.isCrossSigningVerified() ->
                 // This is a self verification and I am the old device (Osborne2)
                 createQrCodeDataForVerifiedDevice(requestId, otherDeviceId)
-            else                                         ->
+            else ->
                 // This is a self verification and I am the new device (Dynabook)
                 createQrCodeDataForUnVerifiedDevice(requestId)
         }
@@ -1142,10 +1164,12 @@ internal class DefaultVerificationService @Inject constructor(
         }
     }
 
-    override fun requestKeyVerificationInDMs(methods: List<VerificationMethod>,
-                                             otherUserId: String,
-                                             roomId: String,
-                                             localId: String?): PendingVerificationRequest {
+    override fun requestKeyVerificationInDMs(
+            methods: List<VerificationMethod>,
+            otherUserId: String,
+            roomId: String,
+            localId: String?
+    ): PendingVerificationRequest {
         Timber.i("## SAS Requesting verification to user: $otherUserId in room $roomId")
 
         val requestsForUser = pendingRequests.getOrPut(otherUserId) { mutableListOf() }
@@ -1312,11 +1336,13 @@ internal class DefaultVerificationService @Inject constructor(
         dispatchRequestUpdated(updated)
     }
 
-    override fun beginKeyVerificationInDMs(method: VerificationMethod,
-                                           transactionId: String,
-                                           roomId: String,
-                                           otherUserId: String,
-                                           otherDeviceId: String): String {
+    override fun beginKeyVerificationInDMs(
+            method: VerificationMethod,
+            transactionId: String,
+            roomId: String,
+            otherUserId: String,
+            otherDeviceId: String
+    ): String {
         if (method == VerificationMethod.SAS) {
             val tx = DefaultOutgoingSASDefaultVerificationTransaction(
                     setDeviceVerificationAction,
@@ -1341,10 +1367,12 @@ internal class DefaultVerificationService @Inject constructor(
         }
     }
 
-    override fun readyPendingVerificationInDMs(methods: List<VerificationMethod>,
-                                               otherUserId: String,
-                                               roomId: String,
-                                               transactionId: String): Boolean {
+    override fun readyPendingVerificationInDMs(
+            methods: List<VerificationMethod>,
+            otherUserId: String,
+            roomId: String,
+            transactionId: String
+    ): Boolean {
         Timber.v("## SAS readyPendingVerificationInDMs $otherUserId room:$roomId tx:$transactionId")
         // Let's find the related request
         val existingRequest = getExistingVerificationRequest(otherUserId, transactionId)
@@ -1383,9 +1411,11 @@ internal class DefaultVerificationService @Inject constructor(
         }
     }
 
-    override fun readyPendingVerification(methods: List<VerificationMethod>,
-                                          otherUserId: String,
-                                          transactionId: String): Boolean {
+    override fun readyPendingVerification(
+            methods: List<VerificationMethod>,
+            otherUserId: String,
+            transactionId: String
+    ): Boolean {
         Timber.v("## SAS readyPendingVerification $otherUserId tx:$transactionId")
         // Let's find the related request
         val existingRequest = getExistingVerificationRequest(otherUserId, transactionId)
@@ -1429,7 +1459,8 @@ internal class DefaultVerificationService @Inject constructor(
             otherDeviceId: String,
             otherUserMethods: List<String>?,
             methods: List<VerificationMethod>,
-            transportCreator: (DefaultVerificationTransaction) -> VerificationTransport): List<String> {
+            transportCreator: (DefaultVerificationTransaction) -> VerificationTransport
+    ): List<String> {
         if (otherUserMethods.isNullOrEmpty()) {
             return emptyList()
         }
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 27bc7643957340efc11441530427c8c9f4c3c3d8..9d19fd137e028c7b1c21c382effdcab1477ace1f 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
@@ -37,7 +37,8 @@ internal abstract class DefaultVerificationTransaction(
         override val transactionId: String,
         override val otherUserId: String,
         override var otherDeviceId: String? = null,
-        override val isIncoming: Boolean) : VerificationTransaction {
+        override val isIncoming: Boolean
+) : VerificationTransaction {
 
     lateinit var transport: VerificationTransport
 
@@ -55,9 +56,12 @@ internal abstract class DefaultVerificationTransaction(
         listeners.remove(listener)
     }
 
-    protected fun trust(canTrustOtherUserMasterKey: Boolean,
-                        toVerifyDeviceIds: List<String>,
-                        eventuallyMarkMyMasterKeyAsTrusted: Boolean, autoDone: Boolean = true) {
+    protected fun trust(
+            canTrustOtherUserMasterKey: Boolean,
+            toVerifyDeviceIds: List<String>,
+            eventuallyMarkMyMasterKeyAsTrusted: Boolean,
+            autoDone: Boolean = true
+    ) {
         Timber.d("## Verification: trust ($otherUserId,$otherDeviceId) , verifiedDevices:$toVerifyDeviceIds")
         Timber.d("## Verification: trust Mark myMSK trusted $eventuallyMarkMyMasterKeyAsTrusted")
 
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 68dd57478e62af81575a51f90ea3c1c7d6253343..1cbaff059aed85ba43437f2f9f386a157cc79da4 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
@@ -314,11 +314,13 @@ internal abstract class SASDefaultVerificationTransaction(
         transport.cancelTransaction(transactionId, otherUserId, otherDeviceId ?: "", code)
     }
 
-    protected fun <T> sendToOther(type: String,
-                                  keyToDevice: VerificationInfo<T>,
-                                  nextState: VerificationTxState,
-                                  onErrorReason: CancelCode,
-                                  onDone: (() -> Unit)?) {
+    protected fun <T> sendToOther(
+            type: String,
+            keyToDevice: VerificationInfo<T>,
+            nextState: VerificationTxState,
+            onErrorReason: CancelCode,
+            onDone: (() -> Unit)?
+    ) {
         transport.sendToOther(type, keyToDevice, nextState, onErrorReason, onDone)
     }
 
@@ -331,11 +333,11 @@ internal abstract class SASDefaultVerificationTransaction(
                 if (shortCodeBytes!!.size < 5) return null
                 return getDecimalCodeRepresentation(shortCodeBytes!!)
             }
-            SasMode.EMOJI   -> {
+            SasMode.EMOJI -> {
                 if (shortCodeBytes!!.size < 6) return null
                 return getEmojiCodeRepresentation(shortCodeBytes!!).joinToString(" ") { it.emoji }
             }
-            else            -> return null
+            else -> return null
         }
     }
 
@@ -360,8 +362,8 @@ internal abstract class SASDefaultVerificationTransaction(
     private fun macUsingAgreedMethod(message: String, info: String): String? {
         return when (accepted?.messageAuthenticationCode?.lowercase(Locale.ROOT)) {
             SAS_MAC_SHA256_LONGKDF -> getSAS().calculateMacLongKdf(message, info)
-            SAS_MAC_SHA256         -> getSAS().calculateMac(message, info)
-            else                   -> null
+            SAS_MAC_SHA256 -> getSAS().calculateMac(message, info)
+            else -> null
         }
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt
index eb1819fe6a95318030847e0ce19f5923897a7fb7..cff3591771b02c986e48e978b660f5e123f698fa 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt
@@ -20,69 +20,69 @@ import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentatio
 
 internal fun getEmojiForCode(code: Int): EmojiRepresentation {
     return when (code % 64) {
-        0             -> EmojiRepresentation("🐶", R.string.verification_emoji_dog, R.drawable.ic_verification_dog)
-        1             -> EmojiRepresentation("🐱", R.string.verification_emoji_cat, R.drawable.ic_verification_cat)
-        2             -> EmojiRepresentation("🦁", R.string.verification_emoji_lion, R.drawable.ic_verification_lion)
-        3             -> EmojiRepresentation("🐎", R.string.verification_emoji_horse, R.drawable.ic_verification_horse)
-        4             -> EmojiRepresentation("🦄", R.string.verification_emoji_unicorn, R.drawable.ic_verification_unicorn)
-        5             -> EmojiRepresentation("🐷", R.string.verification_emoji_pig, R.drawable.ic_verification_pig)
-        6             -> EmojiRepresentation("🐘", R.string.verification_emoji_elephant, R.drawable.ic_verification_elephant)
-        7             -> EmojiRepresentation("🐰", R.string.verification_emoji_rabbit, R.drawable.ic_verification_rabbit)
-        8             -> EmojiRepresentation("🐼", R.string.verification_emoji_panda, R.drawable.ic_verification_panda)
-        9             -> EmojiRepresentation("🐓", R.string.verification_emoji_rooster, R.drawable.ic_verification_rooster)
-        10            -> EmojiRepresentation("🐧", R.string.verification_emoji_penguin, R.drawable.ic_verification_penguin)
-        11            -> EmojiRepresentation("🐢", R.string.verification_emoji_turtle, R.drawable.ic_verification_turtle)
-        12            -> EmojiRepresentation("🐟", R.string.verification_emoji_fish, R.drawable.ic_verification_fish)
-        13            -> EmojiRepresentation("🐙", R.string.verification_emoji_octopus, R.drawable.ic_verification_octopus)
-        14            -> EmojiRepresentation("🦋", R.string.verification_emoji_butterfly, R.drawable.ic_verification_butterfly)
-        15            -> EmojiRepresentation("🌷", R.string.verification_emoji_flower, R.drawable.ic_verification_flower)
-        16            -> EmojiRepresentation("🌳", R.string.verification_emoji_tree, R.drawable.ic_verification_tree)
-        17            -> EmojiRepresentation("🌵", R.string.verification_emoji_cactus, R.drawable.ic_verification_cactus)
-        18            -> EmojiRepresentation("🍄", R.string.verification_emoji_mushroom, R.drawable.ic_verification_mushroom)
-        19            -> EmojiRepresentation("🌏", R.string.verification_emoji_globe, R.drawable.ic_verification_globe)
-        20            -> EmojiRepresentation("🌙", R.string.verification_emoji_moon, R.drawable.ic_verification_moon)
-        21            -> EmojiRepresentation("☁️", R.string.verification_emoji_cloud, R.drawable.ic_verification_cloud)
-        22            -> EmojiRepresentation("🔥", R.string.verification_emoji_fire, R.drawable.ic_verification_fire)
-        23            -> EmojiRepresentation("🍌", R.string.verification_emoji_banana, R.drawable.ic_verification_banana)
-        24            -> EmojiRepresentation("🍎", R.string.verification_emoji_apple, R.drawable.ic_verification_apple)
-        25            -> EmojiRepresentation("🍓", R.string.verification_emoji_strawberry, R.drawable.ic_verification_strawberry)
-        26            -> EmojiRepresentation("🌽", R.string.verification_emoji_corn, R.drawable.ic_verification_corn)
-        27            -> EmojiRepresentation("🍕", R.string.verification_emoji_pizza, R.drawable.ic_verification_pizza)
-        28            -> EmojiRepresentation("🎂", R.string.verification_emoji_cake, R.drawable.ic_verification_cake)
-        29            -> EmojiRepresentation("❤️", R.string.verification_emoji_heart, R.drawable.ic_verification_heart)
-        30            -> EmojiRepresentation("🙂", R.string.verification_emoji_smiley, R.drawable.ic_verification_smiley)
-        31            -> EmojiRepresentation("🤖", R.string.verification_emoji_robot, R.drawable.ic_verification_robot)
-        32            -> EmojiRepresentation("🎩", R.string.verification_emoji_hat, R.drawable.ic_verification_hat)
-        33            -> EmojiRepresentation("👓", R.string.verification_emoji_glasses, R.drawable.ic_verification_glasses)
-        34            -> EmojiRepresentation("🔧", R.string.verification_emoji_spanner, R.drawable.ic_verification_spanner)
-        35            -> EmojiRepresentation("🎅", R.string.verification_emoji_santa, R.drawable.ic_verification_santa)
-        36            -> EmojiRepresentation("👍", R.string.verification_emoji_thumbs_up, R.drawable.ic_verification_thumbs_up)
-        37            -> EmojiRepresentation("☂️", R.string.verification_emoji_umbrella, R.drawable.ic_verification_umbrella)
-        38            -> EmojiRepresentation("⌛", R.string.verification_emoji_hourglass, R.drawable.ic_verification_hourglass)
-        39            -> EmojiRepresentation("⏰", R.string.verification_emoji_clock, R.drawable.ic_verification_clock)
-        40            -> EmojiRepresentation("🎁", R.string.verification_emoji_gift, R.drawable.ic_verification_gift)
-        41            -> EmojiRepresentation("💡", R.string.verification_emoji_light_bulb, R.drawable.ic_verification_light_bulb)
-        42            -> EmojiRepresentation("📕", R.string.verification_emoji_book, R.drawable.ic_verification_book)
-        43            -> EmojiRepresentation("✏️", R.string.verification_emoji_pencil, R.drawable.ic_verification_pencil)
-        44            -> EmojiRepresentation("📎", R.string.verification_emoji_paperclip, R.drawable.ic_verification_paperclip)
-        45            -> EmojiRepresentation("✂️", R.string.verification_emoji_scissors, R.drawable.ic_verification_scissors)
-        46            -> EmojiRepresentation("🔒", R.string.verification_emoji_lock, R.drawable.ic_verification_lock)
-        47            -> EmojiRepresentation("🔑", R.string.verification_emoji_key, R.drawable.ic_verification_key)
-        48            -> EmojiRepresentation("🔨", R.string.verification_emoji_hammer, R.drawable.ic_verification_hammer)
-        49            -> EmojiRepresentation("☎️", R.string.verification_emoji_telephone, R.drawable.ic_verification_phone)
-        50            -> EmojiRepresentation("🏁", R.string.verification_emoji_flag, R.drawable.ic_verification_flag)
-        51            -> EmojiRepresentation("🚂", R.string.verification_emoji_train, R.drawable.ic_verification_train)
-        52            -> EmojiRepresentation("🚲", R.string.verification_emoji_bicycle, R.drawable.ic_verification_bicycle)
-        53            -> EmojiRepresentation("✈️", R.string.verification_emoji_aeroplane, R.drawable.ic_verification_aeroplane)
-        54            -> EmojiRepresentation("🚀", R.string.verification_emoji_rocket, R.drawable.ic_verification_rocket)
-        55            -> EmojiRepresentation("🏆", R.string.verification_emoji_trophy, R.drawable.ic_verification_trophy)
-        56            -> EmojiRepresentation("âš½", R.string.verification_emoji_ball, R.drawable.ic_verification_ball)
-        57            -> EmojiRepresentation("🎸", R.string.verification_emoji_guitar, R.drawable.ic_verification_guitar)
-        58            -> EmojiRepresentation("🎺", R.string.verification_emoji_trumpet, R.drawable.ic_verification_trumpet)
-        59            -> EmojiRepresentation("🔔", R.string.verification_emoji_bell, R.drawable.ic_verification_bell)
-        60            -> EmojiRepresentation("âš“", R.string.verification_emoji_anchor, R.drawable.ic_verification_anchor)
-        61            -> EmojiRepresentation("🎧", R.string.verification_emoji_headphones, R.drawable.ic_verification_headphones)
-        62            -> EmojiRepresentation("📁", R.string.verification_emoji_folder, R.drawable.ic_verification_folder)
+        0 -> EmojiRepresentation("🐶", R.string.verification_emoji_dog, R.drawable.ic_verification_dog)
+        1 -> EmojiRepresentation("🐱", R.string.verification_emoji_cat, R.drawable.ic_verification_cat)
+        2 -> EmojiRepresentation("🦁", R.string.verification_emoji_lion, R.drawable.ic_verification_lion)
+        3 -> EmojiRepresentation("🐎", R.string.verification_emoji_horse, R.drawable.ic_verification_horse)
+        4 -> EmojiRepresentation("🦄", R.string.verification_emoji_unicorn, R.drawable.ic_verification_unicorn)
+        5 -> EmojiRepresentation("🐷", R.string.verification_emoji_pig, R.drawable.ic_verification_pig)
+        6 -> EmojiRepresentation("🐘", R.string.verification_emoji_elephant, R.drawable.ic_verification_elephant)
+        7 -> EmojiRepresentation("🐰", R.string.verification_emoji_rabbit, R.drawable.ic_verification_rabbit)
+        8 -> EmojiRepresentation("🐼", R.string.verification_emoji_panda, R.drawable.ic_verification_panda)
+        9 -> EmojiRepresentation("🐓", R.string.verification_emoji_rooster, R.drawable.ic_verification_rooster)
+        10 -> EmojiRepresentation("🐧", R.string.verification_emoji_penguin, R.drawable.ic_verification_penguin)
+        11 -> EmojiRepresentation("🐢", R.string.verification_emoji_turtle, R.drawable.ic_verification_turtle)
+        12 -> EmojiRepresentation("🐟", R.string.verification_emoji_fish, R.drawable.ic_verification_fish)
+        13 -> EmojiRepresentation("🐙", R.string.verification_emoji_octopus, R.drawable.ic_verification_octopus)
+        14 -> EmojiRepresentation("🦋", R.string.verification_emoji_butterfly, R.drawable.ic_verification_butterfly)
+        15 -> EmojiRepresentation("🌷", R.string.verification_emoji_flower, R.drawable.ic_verification_flower)
+        16 -> EmojiRepresentation("🌳", R.string.verification_emoji_tree, R.drawable.ic_verification_tree)
+        17 -> EmojiRepresentation("🌵", R.string.verification_emoji_cactus, R.drawable.ic_verification_cactus)
+        18 -> EmojiRepresentation("🍄", R.string.verification_emoji_mushroom, R.drawable.ic_verification_mushroom)
+        19 -> EmojiRepresentation("🌏", R.string.verification_emoji_globe, R.drawable.ic_verification_globe)
+        20 -> EmojiRepresentation("🌙", R.string.verification_emoji_moon, R.drawable.ic_verification_moon)
+        21 -> EmojiRepresentation("☁️", R.string.verification_emoji_cloud, R.drawable.ic_verification_cloud)
+        22 -> EmojiRepresentation("🔥", R.string.verification_emoji_fire, R.drawable.ic_verification_fire)
+        23 -> EmojiRepresentation("🍌", R.string.verification_emoji_banana, R.drawable.ic_verification_banana)
+        24 -> EmojiRepresentation("🍎", R.string.verification_emoji_apple, R.drawable.ic_verification_apple)
+        25 -> EmojiRepresentation("🍓", R.string.verification_emoji_strawberry, R.drawable.ic_verification_strawberry)
+        26 -> EmojiRepresentation("🌽", R.string.verification_emoji_corn, R.drawable.ic_verification_corn)
+        27 -> EmojiRepresentation("🍕", R.string.verification_emoji_pizza, R.drawable.ic_verification_pizza)
+        28 -> EmojiRepresentation("🎂", R.string.verification_emoji_cake, R.drawable.ic_verification_cake)
+        29 -> EmojiRepresentation("❤️", R.string.verification_emoji_heart, R.drawable.ic_verification_heart)
+        30 -> EmojiRepresentation("🙂", R.string.verification_emoji_smiley, R.drawable.ic_verification_smiley)
+        31 -> EmojiRepresentation("🤖", R.string.verification_emoji_robot, R.drawable.ic_verification_robot)
+        32 -> EmojiRepresentation("🎩", R.string.verification_emoji_hat, R.drawable.ic_verification_hat)
+        33 -> EmojiRepresentation("👓", R.string.verification_emoji_glasses, R.drawable.ic_verification_glasses)
+        34 -> EmojiRepresentation("🔧", R.string.verification_emoji_spanner, R.drawable.ic_verification_spanner)
+        35 -> EmojiRepresentation("🎅", R.string.verification_emoji_santa, R.drawable.ic_verification_santa)
+        36 -> EmojiRepresentation("👍", R.string.verification_emoji_thumbs_up, R.drawable.ic_verification_thumbs_up)
+        37 -> EmojiRepresentation("☂️", R.string.verification_emoji_umbrella, R.drawable.ic_verification_umbrella)
+        38 -> EmojiRepresentation("⌛", R.string.verification_emoji_hourglass, R.drawable.ic_verification_hourglass)
+        39 -> EmojiRepresentation("⏰", R.string.verification_emoji_clock, R.drawable.ic_verification_clock)
+        40 -> EmojiRepresentation("🎁", R.string.verification_emoji_gift, R.drawable.ic_verification_gift)
+        41 -> EmojiRepresentation("💡", R.string.verification_emoji_light_bulb, R.drawable.ic_verification_light_bulb)
+        42 -> EmojiRepresentation("📕", R.string.verification_emoji_book, R.drawable.ic_verification_book)
+        43 -> EmojiRepresentation("✏️", R.string.verification_emoji_pencil, R.drawable.ic_verification_pencil)
+        44 -> EmojiRepresentation("📎", R.string.verification_emoji_paperclip, R.drawable.ic_verification_paperclip)
+        45 -> EmojiRepresentation("✂️", R.string.verification_emoji_scissors, R.drawable.ic_verification_scissors)
+        46 -> EmojiRepresentation("🔒", R.string.verification_emoji_lock, R.drawable.ic_verification_lock)
+        47 -> EmojiRepresentation("🔑", R.string.verification_emoji_key, R.drawable.ic_verification_key)
+        48 -> EmojiRepresentation("🔨", R.string.verification_emoji_hammer, R.drawable.ic_verification_hammer)
+        49 -> EmojiRepresentation("☎️", R.string.verification_emoji_telephone, R.drawable.ic_verification_phone)
+        50 -> EmojiRepresentation("🏁", R.string.verification_emoji_flag, R.drawable.ic_verification_flag)
+        51 -> EmojiRepresentation("🚂", R.string.verification_emoji_train, R.drawable.ic_verification_train)
+        52 -> EmojiRepresentation("🚲", R.string.verification_emoji_bicycle, R.drawable.ic_verification_bicycle)
+        53 -> EmojiRepresentation("✈️", R.string.verification_emoji_aeroplane, R.drawable.ic_verification_aeroplane)
+        54 -> EmojiRepresentation("🚀", R.string.verification_emoji_rocket, R.drawable.ic_verification_rocket)
+        55 -> EmojiRepresentation("🏆", R.string.verification_emoji_trophy, R.drawable.ic_verification_trophy)
+        56 -> EmojiRepresentation("âš½", R.string.verification_emoji_ball, R.drawable.ic_verification_ball)
+        57 -> EmojiRepresentation("🎸", R.string.verification_emoji_guitar, R.drawable.ic_verification_guitar)
+        58 -> EmojiRepresentation("🎺", R.string.verification_emoji_trumpet, R.drawable.ic_verification_trumpet)
+        59 -> EmojiRepresentation("🔔", R.string.verification_emoji_bell, R.drawable.ic_verification_bell)
+        60 -> EmojiRepresentation("âš“", R.string.verification_emoji_anchor, R.drawable.ic_verification_anchor)
+        61 -> EmojiRepresentation("🎧", R.string.verification_emoji_headphones, R.drawable.ic_verification_headphones)
+        62 -> EmojiRepresentation("📁", R.string.verification_emoji_folder, R.drawable.ic_verification_folder)
         /* 63 */ else -> EmojiRepresentation("📌", R.string.verification_emoji_pin, R.drawable.ic_verification_pin)
     }
 }
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 3ddb0ca758038f50c9520931c3890b69327702b2..0b9287cb052e23a1c388853e5098425665e8bd79 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
@@ -63,12 +63,14 @@ internal interface VerificationInfoAccept : VerificationInfo<ValidVerificationIn
 
 internal interface VerificationInfoAcceptFactory {
 
-    fun create(tid: String,
-               keyAgreementProtocol: String,
-               hash: String,
-               commitment: String,
-               messageAuthenticationCode: String,
-               shortAuthenticationStrings: List<String>): VerificationInfoAccept
+    fun create(
+            tid: String,
+            keyAgreementProtocol: String,
+            hash: String,
+            commitment: String,
+            messageAuthenticationCode: String,
+            shortAuthenticationStrings: List<String>
+    ): VerificationInfoAccept
 }
 
 internal data class ValidVerificationInfoAccept(
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 d71bd7359ee8a5cc932f58d20a5ec0faff38e67a..66591fe00f05c6b0cf639d844624d56e1ea0eff6 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
@@ -68,7 +68,7 @@ internal interface VerificationInfoStart : VerificationInfo<ValidVerificationInf
         val validFromDevice = fromDevice?.takeIf { it.isNotEmpty() } ?: return null
 
         return when (method) {
-            VERIFICATION_METHOD_SAS         -> {
+            VERIFICATION_METHOD_SAS -> {
                 val validKeyAgreementProtocols = keyAgreementProtocols?.takeIf { it.isNotEmpty() } ?: return null
                 val validHashes = hashes?.takeIf { it.contains("sha256") } ?: return null
                 val validMessageAuthenticationCodes = messageAuthenticationCodes
@@ -98,14 +98,15 @@ internal interface VerificationInfoStart : VerificationInfo<ValidVerificationInf
                         validSharedSecret
                 )
             }
-            else                            -> null
+            else -> null
         }
     }
 }
 
 internal sealed class ValidVerificationInfoStart(
         open val transactionId: String,
-        open val fromDevice: String) {
+        open val fromDevice: String
+) {
     data class SasVerificationInfoStart(
             override val transactionId: String,
             override val fromDevice: 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 303b6c5839ffbe23dbbd3edfd98490ed7953eee1..9f123f0c08638163b26a6c3288793c29656fb693 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
@@ -131,7 +131,7 @@ internal class VerificationMessageProcessor @Inject constructor(
             EventType.KEY_VERIFICATION_DONE -> {
                 verificationService.onRoomEvent(event)
             }
-            EventType.MESSAGE               -> {
+            EventType.MESSAGE -> {
                 if (MessageType.MSGTYPE_VERIFICATION_REQUEST == event.getClearContent().toModel<MessageContent>()?.msgType) {
                     verificationService.onRoomRequestReceived(event)
                 }
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 c12aea9d52df4c51baab15eceddcc829cb35ea1d..5314c238707e249787fd8907e055205b60c904cb 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
@@ -28,69 +28,101 @@ internal interface VerificationTransport {
     /**
      * Sends a message.
      */
-    fun <T> sendToOther(type: String,
-                        verificationInfo: VerificationInfo<T>,
-                        nextState: VerificationTxState,
-                        onErrorReason: CancelCode,
-                        onDone: (() -> Unit)?)
+    fun <T> sendToOther(
+            type: String,
+            verificationInfo: VerificationInfo<T>,
+            nextState: VerificationTxState,
+            onErrorReason: CancelCode,
+            onDone: (() -> Unit)?
+    )
 
     /**
+     * @param supportedMethods list of supported method by this client
+     * @param localId a local Id
+     * @param otherUserId the user id to send the verification request to
+     * @param roomId a room Id to use to send verification message
+     * @param toDevices list of device Ids
      * @param callback will be called with eventId and ValidVerificationInfoRequest in case of success
      */
-    fun sendVerificationRequest(supportedMethods: List<String>,
-                                localId: String,
-                                otherUserId: String,
-                                roomId: String?,
-                                toDevices: List<String>?,
-                                callback: (String?, ValidVerificationInfoRequest?) -> Unit)
+    fun sendVerificationRequest(
+            supportedMethods: List<String>,
+            localId: String,
+            otherUserId: String,
+            roomId: String?,
+            toDevices: List<String>?,
+            callback: (String?, ValidVerificationInfoRequest?) -> Unit
+    )
 
-    fun cancelTransaction(transactionId: String,
-                          otherUserId: String,
-                          otherUserDeviceId: String?,
-                          code: CancelCode)
+    fun cancelTransaction(
+            transactionId: String,
+            otherUserId: String,
+            otherUserDeviceId: String?,
+            code: CancelCode
+    )
 
-    fun done(transactionId: String,
-             onDone: (() -> Unit)?)
+    fun cancelTransaction(
+            transactionId: String,
+            otherUserId: String,
+            otherUserDeviceIds: List<String>,
+            code: CancelCode
+    )
+
+    fun done(
+            transactionId: String,
+            onDone: (() -> Unit)?
+    )
 
     /**
      * Creates an accept message suitable for this transport.
      */
-    fun createAccept(tid: String,
-                     keyAgreementProtocol: String,
-                     hash: String,
-                     commitment: String,
-                     messageAuthenticationCode: String,
-                     shortAuthenticationStrings: List<String>): VerificationInfoAccept
+    fun createAccept(
+            tid: String,
+            keyAgreementProtocol: String,
+            hash: String,
+            commitment: String,
+            messageAuthenticationCode: String,
+            shortAuthenticationStrings: List<String>
+    ): VerificationInfoAccept
 
-    fun createKey(tid: String,
-                  pubKey: String): VerificationInfoKey
+    fun createKey(
+            tid: String,
+            pubKey: String
+    ): VerificationInfoKey
 
     /**
      * Create start for SAS verification.
      */
-    fun createStartForSas(fromDevice: String,
-                          transactionId: String,
-                          keyAgreementProtocols: List<String>,
-                          hashes: List<String>,
-                          messageAuthenticationCodes: List<String>,
-                          shortAuthenticationStrings: List<String>): VerificationInfoStart
+    fun createStartForSas(
+            fromDevice: String,
+            transactionId: String,
+            keyAgreementProtocols: List<String>,
+            hashes: List<String>,
+            messageAuthenticationCodes: List<String>,
+            shortAuthenticationStrings: List<String>
+    ): VerificationInfoStart
 
     /**
      * Create start for QR code verification.
      */
-    fun createStartForQrCode(fromDevice: String,
-                             transactionId: String,
-                             sharedSecret: String): VerificationInfoStart
+    fun createStartForQrCode(
+            fromDevice: String,
+            transactionId: String,
+            sharedSecret: String
+    ): VerificationInfoStart
 
     fun createMac(tid: String, mac: Map<String, String>, keys: String): VerificationInfoMac
 
-    fun createReady(tid: String,
-                    fromDevice: String,
-                    methods: List<String>): VerificationInfoReady
+    fun createReady(
+            tid: String,
+            fromDevice: String,
+            methods: List<String>
+    ): VerificationInfoReady
 
     // TODO Refactor
-    fun sendVerificationReady(keyReq: VerificationInfoReady,
-                              otherUserId: String,
-                              otherDeviceId: String?,
-                              callback: (() -> Unit)?)
+    fun sendVerificationReady(
+            keyReq: VerificationInfoReady,
+            otherUserId: String,
+            otherDeviceId: String?,
+            callback: (() -> Unit)?
+    )
 }
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 e32828af23850154040aa9db82f8e738153de544..f38a604890bc413d0168ed81fcf8e473c78b785d 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
@@ -61,11 +61,13 @@ internal class VerificationTransportRoomMessage(
     private val verificationSenderScope = CoroutineScope(cryptoCoroutineScope.coroutineContext + dispatcher)
     private val sequencer = SemaphoreCoroutineSequencer()
 
-    override fun <T> sendToOther(type: String,
-                                 verificationInfo: VerificationInfo<T>,
-                                 nextState: VerificationTxState,
-                                 onErrorReason: CancelCode,
-                                 onDone: (() -> Unit)?) {
+    override fun <T> sendToOther(
+            type: String,
+            verificationInfo: VerificationInfo<T>,
+            nextState: VerificationTxState,
+            onErrorReason: CancelCode,
+            onDone: (() -> Unit)?
+    ) {
         Timber.d("## SAS sending msg type $type")
         Timber.v("## SAS sending msg info $verificationInfo")
         val event = createEventAndLocalEcho(
@@ -92,12 +94,14 @@ internal class VerificationTransportRoomMessage(
         }
     }
 
-    override fun sendVerificationRequest(supportedMethods: List<String>,
-                                         localId: String,
-                                         otherUserId: String,
-                                         roomId: String?,
-                                         toDevices: List<String>?,
-                                         callback: (String?, ValidVerificationInfoRequest?) -> Unit) {
+    override fun sendVerificationRequest(
+            supportedMethods: List<String>,
+            localId: String,
+            otherUserId: String,
+            roomId: String?,
+            toDevices: List<String>?,
+            callback: (String?, ValidVerificationInfoRequest?) -> Unit
+    ) {
         Timber.d("## SAS sending verification request with supported methods: $supportedMethods")
         // This transport requires a room
         requireNotNull(roomId)
@@ -160,8 +164,17 @@ internal class VerificationTransportRoomMessage(
         }
     }
 
-    override fun done(transactionId: String,
-                      onDone: (() -> Unit)?) {
+    override fun cancelTransaction(
+            transactionId: String,
+            otherUserId: String,
+            otherUserDeviceIds: List<String>,
+            code: CancelCode
+    ) = cancelTransaction(transactionId, otherUserId, null, code)
+
+    override fun done(
+            transactionId: String,
+            onDone: (() -> Unit)?
+    ) {
         Timber.d("## SAS sending done for $transactionId")
         val event = createEventAndLocalEcho(
                 type = EventType.KEY_VERIFICATION_DONE,
@@ -188,12 +201,14 @@ internal class VerificationTransportRoomMessage(
         }
     }
 
-    override fun createAccept(tid: String,
-                              keyAgreementProtocol: String,
-                              hash: String,
-                              commitment: String,
-                              messageAuthenticationCode: String,
-                              shortAuthenticationStrings: List<String>): VerificationInfoAccept =
+    override fun createAccept(
+            tid: String,
+            keyAgreementProtocol: String,
+            hash: String,
+            commitment: String,
+            messageAuthenticationCode: String,
+            shortAuthenticationStrings: List<String>
+    ): VerificationInfoAccept =
             MessageVerificationAcceptContent.create(
                     tid,
                     keyAgreementProtocol,
@@ -207,12 +222,14 @@ internal class VerificationTransportRoomMessage(
 
     override fun createMac(tid: String, mac: Map<String, String>, keys: String) = MessageVerificationMacContent.create(tid, mac, keys)
 
-    override fun createStartForSas(fromDevice: String,
-                                   transactionId: String,
-                                   keyAgreementProtocols: List<String>,
-                                   hashes: List<String>,
-                                   messageAuthenticationCodes: List<String>,
-                                   shortAuthenticationStrings: List<String>): VerificationInfoStart {
+    override fun createStartForSas(
+            fromDevice: String,
+            transactionId: String,
+            keyAgreementProtocols: List<String>,
+            hashes: List<String>,
+            messageAuthenticationCodes: List<String>,
+            shortAuthenticationStrings: List<String>
+    ): VerificationInfoStart {
         return MessageVerificationStartContent(
                 fromDevice,
                 hashes,
@@ -228,9 +245,11 @@ internal class VerificationTransportRoomMessage(
         )
     }
 
-    override fun createStartForQrCode(fromDevice: String,
-                                      transactionId: String,
-                                      sharedSecret: String): VerificationInfoStart {
+    override fun createStartForQrCode(
+            fromDevice: String,
+            transactionId: String,
+            sharedSecret: String
+    ): VerificationInfoStart {
         return MessageVerificationStartContent(
                 fromDevice,
                 null,
@@ -271,10 +290,12 @@ internal class VerificationTransportRoomMessage(
         }
     }
 
-    override fun sendVerificationReady(keyReq: VerificationInfoReady,
-                                       otherUserId: String,
-                                       otherDeviceId: String?,
-                                       callback: (() -> Unit)?) {
+    override fun sendVerificationReady(
+            keyReq: VerificationInfoReady,
+            otherUserId: String,
+            otherDeviceId: String?,
+            callback: (() -> Unit)?
+    ) {
         // Not applicable (send event is called directly)
         Timber.w("## SAS ignored verification ready with methods: ${keyReq.methods}")
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt
index bc24ef2966ef5e6b9549517568b973430328d58b..861a7a3a77a3a6300571b3dd06505ad7fc320ecf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt
@@ -47,12 +47,14 @@ internal class VerificationTransportToDevice(
         private val clock: Clock,
 ) : VerificationTransport {
 
-    override fun sendVerificationRequest(supportedMethods: List<String>,
-                                         localId: String,
-                                         otherUserId: String,
-                                         roomId: String?,
-                                         toDevices: List<String>?,
-                                         callback: (String?, ValidVerificationInfoRequest?) -> Unit) {
+    override fun sendVerificationRequest(
+            supportedMethods: List<String>,
+            localId: String,
+            otherUserId: String,
+            roomId: String?,
+            toDevices: List<String>?,
+            callback: (String?, ValidVerificationInfoRequest?) -> Unit
+    ) {
         Timber.d("## SAS sending verification request with supported methods: $supportedMethods")
         val contentMap = MXUsersDevicesMap<Any>()
         val validKeyReq = ValidVerificationInfoRequest(
@@ -86,10 +88,12 @@ internal class VerificationTransportToDevice(
                 .executeBy(taskExecutor)
     }
 
-    override fun sendVerificationReady(keyReq: VerificationInfoReady,
-                                       otherUserId: String,
-                                       otherDeviceId: String?,
-                                       callback: (() -> Unit)?) {
+    override fun sendVerificationReady(
+            keyReq: VerificationInfoReady,
+            otherUserId: String,
+            otherDeviceId: String?,
+            callback: (() -> Unit)?
+    ) {
         Timber.d("## SAS sending verification ready with methods: ${keyReq.methods}")
         val contentMap = MXUsersDevicesMap<Any>()
 
@@ -111,11 +115,13 @@ internal class VerificationTransportToDevice(
                 .executeBy(taskExecutor)
     }
 
-    override fun <T> sendToOther(type: String,
-                                 verificationInfo: VerificationInfo<T>,
-                                 nextState: VerificationTxState,
-                                 onErrorReason: CancelCode,
-                                 onDone: (() -> Unit)?) {
+    override fun <T> sendToOther(
+            type: String,
+            verificationInfo: VerificationInfo<T>,
+            nextState: VerificationTxState,
+            onErrorReason: CancelCode,
+            onDone: (() -> Unit)?
+    ) {
         Timber.d("## SAS sending msg type $type")
         Timber.v("## SAS sending msg info $verificationInfo")
         val stateBeforeCall = tx?.state
@@ -193,12 +199,35 @@ internal class VerificationTransportToDevice(
                 .executeBy(taskExecutor)
     }
 
-    override fun createAccept(tid: String,
-                              keyAgreementProtocol: String,
-                              hash: String,
-                              commitment: String,
-                              messageAuthenticationCode: String,
-                              shortAuthenticationStrings: List<String>): VerificationInfoAccept = KeyVerificationAccept.create(
+    override fun cancelTransaction(transactionId: String, otherUserId: String, otherUserDeviceIds: List<String>, code: CancelCode) {
+        Timber.d("## SAS canceling transaction $transactionId for reason $code")
+        val cancelMessage = KeyVerificationCancel.create(transactionId, code)
+        val contentMap = MXUsersDevicesMap<Any>()
+        val messages = otherUserDeviceIds.associateWith { cancelMessage }
+        contentMap.setObjects(otherUserId, messages)
+        sendToDeviceTask
+                .configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap)) {
+                    this.callback = object : MatrixCallback<Unit> {
+                        override fun onSuccess(data: Unit) {
+                            Timber.v("## SAS verification [$transactionId] canceled for reason ${code.value}")
+                        }
+
+                        override fun onFailure(failure: Throwable) {
+                            Timber.e(failure, "## SAS verification [$transactionId] failed to cancel.")
+                        }
+                    }
+                }
+                .executeBy(taskExecutor)
+    }
+
+    override fun createAccept(
+            tid: String,
+            keyAgreementProtocol: String,
+            hash: String,
+            commitment: String,
+            messageAuthenticationCode: String,
+            shortAuthenticationStrings: List<String>
+    ): VerificationInfoAccept = KeyVerificationAccept.create(
             tid,
             keyAgreementProtocol,
             hash,
@@ -211,12 +240,14 @@ internal class VerificationTransportToDevice(
 
     override fun createMac(tid: String, mac: Map<String, String>, keys: String) = KeyVerificationMac.create(tid, mac, keys)
 
-    override fun createStartForSas(fromDevice: String,
-                                   transactionId: String,
-                                   keyAgreementProtocols: List<String>,
-                                   hashes: List<String>,
-                                   messageAuthenticationCodes: List<String>,
-                                   shortAuthenticationStrings: List<String>): VerificationInfoStart {
+    override fun createStartForSas(
+            fromDevice: String,
+            transactionId: String,
+            keyAgreementProtocols: List<String>,
+            hashes: List<String>,
+            messageAuthenticationCodes: List<String>,
+            shortAuthenticationStrings: List<String>
+    ): VerificationInfoStart {
         return KeyVerificationStart(
                 fromDevice,
                 VERIFICATION_METHOD_SAS,
@@ -229,9 +260,11 @@ internal class VerificationTransportToDevice(
         )
     }
 
-    override fun createStartForQrCode(fromDevice: String,
-                                      transactionId: String,
-                                      sharedSecret: String): VerificationInfoStart {
+    override fun createStartForQrCode(
+            fromDevice: String,
+            transactionId: String,
+            sharedSecret: String
+    ): VerificationInfoStart {
         return KeyVerificationStart(
                 fromDevice,
                 VERIFICATION_METHOD_RECIPROCATE,
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 b1ad4d87b6a56acec89926cb826b7692ea48e96d..690ac122687c5835e38b7c673cfbd8a2a1ca3f16 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
@@ -94,7 +94,7 @@ internal class DefaultQrCodeVerificationTransaction(
 
         // Check the other device view of my MSK
         when (otherQrCodeData) {
-            is QrCodeData.VerifyingAnotherUser             -> {
+            is QrCodeData.VerifyingAnotherUser -> {
                 // key2 (aka otherUserMasterCrossSigningPublicKey) is what the one displaying the QR code (other user) think my MSK is.
                 // Let's check that it's correct
                 // If not -> Cancel
@@ -104,7 +104,7 @@ internal class DefaultQrCodeVerificationTransaction(
                     return
                 } else Unit
             }
-            is QrCodeData.SelfVerifyingMasterKeyTrusted    -> {
+            is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
                 // key1 (aka userMasterCrossSigningPublicKey) is the session displaying the QR code view of our MSK.
                 // Let's check that I see the same MSK
                 // If not -> Cancel
@@ -135,7 +135,7 @@ internal class DefaultQrCodeVerificationTransaction(
 
         // Let's now check the other user/device key material
         when (otherQrCodeData) {
-            is QrCodeData.VerifyingAnotherUser             -> {
+            is QrCodeData.VerifyingAnotherUser -> {
                 // key1(aka userMasterCrossSigningPublicKey) is the MSK of the one displaying the QR code (i.e other user)
                 // Let's check that it matches what I think it should be
                 if (otherQrCodeData.userMasterCrossSigningPublicKey
@@ -149,7 +149,7 @@ internal class DefaultQrCodeVerificationTransaction(
                     Unit
                 }
             }
-            is QrCodeData.SelfVerifyingMasterKeyTrusted    -> {
+            is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
                 // key2 (aka otherDeviceKey) is my current device key in POV of the one displaying the QR code (i.e other device)
                 // Let's check that it's correct
                 if (otherQrCodeData.otherDeviceKey
@@ -259,11 +259,11 @@ internal class DefaultQrCodeVerificationTransaction(
 
     override fun otherUserScannedMyQrCode() {
         when (qrCodeData) {
-            is QrCodeData.VerifyingAnotherUser             -> {
+            is QrCodeData.VerifyingAnotherUser -> {
                 // Alice telling Bob that the code was scanned successfully is sufficient for Bob to trust Alice's key,
                 trust(true, emptyList(), false)
             }
-            is QrCodeData.SelfVerifyingMasterKeyTrusted    -> {
+            is QrCodeData.SelfVerifyingMasterKeyTrusted -> {
                 // I now know that I have the correct device key for other session,
                 // and can sign it with the self-signing key and upload the signature
                 trust(false, listOf(otherDeviceId ?: ""), false)
@@ -272,7 +272,7 @@ internal class DefaultQrCodeVerificationTransaction(
                 // I now know that i can trust my MSK
                 trust(true, emptyList(), true)
             }
-            null                                           -> Unit
+            null -> Unit
         }
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt
index b80c29c244af1b3b057dda558a4d8f47329c346d..a0202485d62c4461167631cc98f9579581293253 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt
@@ -36,8 +36,8 @@ internal fun QrCodeData.toEncodedString(): String {
 
     // Mode
     result += when (this) {
-        is QrCodeData.VerifyingAnotherUser             -> 0
-        is QrCodeData.SelfVerifyingMasterKeyTrusted    -> 1
+        is QrCodeData.VerifyingAnotherUser -> 0
+        is QrCodeData.SelfVerifyingMasterKeyTrusted -> 1
         is QrCodeData.SelfVerifyingMasterKeyNotTrusted -> 2
     }.toByte()
 
@@ -119,9 +119,9 @@ internal fun String.toQrCodeData(): QrCodeData? {
     val secret = byteArray.copyOfRange(cursor, byteArray.size).toBase64NoPadding()
 
     return when (mode) {
-        0    -> QrCodeData.VerifyingAnotherUser(transactionId, key1, key2, secret)
-        1    -> QrCodeData.SelfVerifyingMasterKeyTrusted(transactionId, key1, key2, secret)
-        2    -> QrCodeData.SelfVerifyingMasterKeyNotTrusted(transactionId, key1, key2, secret)
+        0 -> QrCodeData.VerifyingAnotherUser(transactionId, key1, key2, secret)
+        1 -> QrCodeData.SelfVerifyingMasterKeyTrusted(transactionId, key1, key2, secret)
+        2 -> QrCodeData.SelfVerifyingMasterKeyNotTrusted(transactionId, key1, key2, secret)
         else -> null
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt
index 751992fa7f8839c614dd11a2eeb5c219679ef66f..d1ca4f48a6608cc1110dee4d21cbc72e83aacc57 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt
@@ -19,10 +19,9 @@ package org.matrix.android.sdk.internal.database
 import com.zhuinden.monarchy.Monarchy
 import io.realm.RealmConfiguration
 import io.realm.RealmResults
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
 import org.matrix.android.sdk.internal.database.mapper.asDomain
 import org.matrix.android.sdk.internal.database.model.EventEntity
 import org.matrix.android.sdk.internal.database.model.EventInsertEntity
@@ -33,69 +32,64 @@ import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor
 import timber.log.Timber
 import javax.inject.Inject
 
-internal class EventInsertLiveObserver @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration,
-                                                           private val processors: Set<@JvmSuppressWildcards EventInsertLiveProcessor>) :
+internal class EventInsertLiveObserver @Inject constructor(
+        @SessionDatabase realmConfiguration: RealmConfiguration,
+        private val processors: Set<@JvmSuppressWildcards EventInsertLiveProcessor>
+) :
         RealmLiveEntityObserver<EventInsertEntity>(realmConfiguration) {
 
+    private val lock = Mutex()
+
     override val query = Monarchy.Query {
         it.where(EventInsertEntity::class.java).equalTo(EventInsertEntityFields.CAN_BE_PROCESSED, true)
     }
 
-    private val onResultsChangedFlow = MutableSharedFlow<RealmResults<EventInsertEntity>>()
-
-    init {
-        onResultsChangedFlow
-                .onEach { handleChange(it) }
-                .launchIn(observerScope)
-    }
-
     override fun onChange(results: RealmResults<EventInsertEntity>) {
-        if (!results.isLoaded || results.isEmpty()) {
-            return
-        }
-        observerScope.launch { onResultsChangedFlow.emit(results) }
-    }
-
-    private suspend fun handleChange(results: RealmResults<EventInsertEntity>) {
-        val idsToDeleteAfterProcess = ArrayList<String>()
-        val filteredEvents = ArrayList<EventInsertEntity>(results.size)
-        Timber.v("EventInsertEntity updated with ${results.size} results in db")
-        results.forEach {
-            if (shouldProcess(it)) {
-                // don't use copy from realm over there
-                val copiedEvent = EventInsertEntity(
-                        eventId = it.eventId,
-                        eventType = it.eventType
-                ).apply {
-                    insertType = it.insertType
+        observerScope.launch {
+            lock.withLock {
+                if (!results.isLoaded || results.isEmpty()) {
+                    return@withLock
                 }
-                filteredEvents.add(copiedEvent)
-            }
-            idsToDeleteAfterProcess.add(it.eventId)
-        }
-
-        awaitTransaction(realmConfiguration) { realm ->
-            Timber.v("##Transaction: There are ${filteredEvents.size} events to process ")
-            filteredEvents.forEach { eventInsert ->
-                val eventId = eventInsert.eventId
-                val event = EventEntity.where(realm, eventId).findFirst()
-                if (event == null) {
-                    Timber.v("Event $eventId not found")
-                    return@forEach
+                val idsToDeleteAfterProcess = ArrayList<String>()
+                val filteredEvents = ArrayList<EventInsertEntity>(results.size)
+                Timber.v("EventInsertEntity updated with ${results.size} results in db")
+                results.forEach {
+                    if (shouldProcess(it)) {
+                        // don't use copy from realm over there
+                        val copiedEvent = EventInsertEntity(
+                                eventId = it.eventId,
+                                eventType = it.eventType
+                        ).apply {
+                            insertType = it.insertType
+                        }
+                        filteredEvents.add(copiedEvent)
+                    }
+                    idsToDeleteAfterProcess.add(it.eventId)
                 }
-                val domainEvent = event.asDomain()
-                processors.filter {
-                    it.shouldProcess(eventId, domainEvent.getClearType(), eventInsert.insertType)
-                }.forEach {
-                    it.process(realm, domainEvent)
+                awaitTransaction(realmConfiguration) { realm ->
+                    Timber.v("##Transaction: There are ${filteredEvents.size} events to process ")
+                    filteredEvents.forEach { eventInsert ->
+                        val eventId = eventInsert.eventId
+                        val event = EventEntity.where(realm, eventId).findFirst()
+                        if (event == null) {
+                            Timber.v("Event $eventId not found")
+                            return@forEach
+                        }
+                        val domainEvent = event.asDomain()
+                        processors.filter {
+                            it.shouldProcess(eventId, domainEvent.getClearType(), eventInsert.insertType)
+                        }.forEach {
+                            it.process(realm, domainEvent)
+                        }
+                    }
+                    realm.where(EventInsertEntity::class.java)
+                            .`in`(EventInsertEntityFields.EVENT_ID, idsToDeleteAfterProcess.toTypedArray())
+                            .findAll()
+                            .deleteAllFromRealm()
                 }
+                processors.forEach { it.onPostProcess() }
             }
-            realm.where(EventInsertEntity::class.java)
-                    .`in`(EventInsertEntityFields.EVENT_ID, idsToDeleteAfterProcess.toTypedArray())
-                    .findAll()
-                    .deleteAllFromRealm()
         }
-        processors.forEach { it.onPostProcess() }
     }
 
     private fun shouldProcess(eventInsertEntity: EventInsertEntity): Boolean {
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 392c1a7185a98df3ac69dc0af04faae422df5570..b3a039d11927f9badf9b04d7df0980acd4c964ba 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
@@ -38,8 +38,10 @@ import javax.inject.Inject
  * then we generate a random secret key. The database key is encrypted with the secret key; The secret
  * key is encrypted with the public RSA key and stored with the encrypted key in the shared pref
  */
-internal class RealmKeysUtils @Inject constructor(context: Context,
-                                                  private val secretStoringUtils: SecretStoringUtils) {
+internal class RealmKeysUtils @Inject constructor(
+        context: Context,
+        private val secretStoringUtils: SecretStoringUtils
+) {
 
     private val rng = SecureRandom()
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmQueryLatch.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmQueryLatch.kt
index c9c797304ad7e52089402bda6af90735b26cf43d..c5ca861e9bdd4ecf0d642a9f6304ce63eb838cfe 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmQueryLatch.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmQueryLatch.kt
@@ -27,9 +27,11 @@ import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.withContext
 import kotlinx.coroutines.withTimeout
 
-internal suspend fun <T> awaitNotEmptyResult(realmConfiguration: RealmConfiguration,
-                                             timeoutMillis: Long,
-                                             builder: (Realm) -> RealmQuery<T>) {
+internal suspend fun <T> awaitNotEmptyResult(
+        realmConfiguration: RealmConfiguration,
+        timeoutMillis: Long,
+        builder: (Realm) -> RealmQuery<T>
+) {
     withTimeout(timeoutMillis) {
         // Confine Realm interaction to a single thread with Looper.
         withContext(Dispatchers.Main) {
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 55bccfd1ec69775d60c2d951cab7fe37a5dad786..6a8589bc5e26bafdd377cab9b15a055b6e7223e9 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
@@ -46,6 +46,8 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo025
 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo026
 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo027
 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo028
+import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo029
+import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo030
 import org.matrix.android.sdk.internal.util.Normalizer
 import timber.log.Timber
 import javax.inject.Inject
@@ -60,7 +62,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
     override fun equals(other: Any?) = other is RealmSessionStoreMigration
     override fun hashCode() = 1000
 
-    val schemaVersion = 28L
+    val schemaVersion = 30L
 
     override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
         Timber.d("Migrating Realm Session from $oldVersion to $newVersion")
@@ -93,5 +95,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
         if (oldVersion < 26) MigrateSessionTo026(realm).perform()
         if (oldVersion < 27) MigrateSessionTo027(realm).perform()
         if (oldVersion < 28) MigrateSessionTo028(realm).perform()
+        if (oldVersion < 29) MigrateSessionTo029(realm).perform()
+        if (oldVersion < 30) MigrateSessionTo030(realm).perform()
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt
index 08d55b5647fac964c05945963e98599f3c67a705..949dd5daa1de60d76e2cd0f087c411a2d9b1f632 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt
@@ -44,7 +44,8 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
         @SessionFilesDirectory val directory: File,
         @SessionId val sessionId: String,
         @UserMd5 val userMd5: String,
-        context: Context) {
+        context: Context
+) {
 
     // Keep legacy preferences name for compatibility reason
     private val sharedPreferences = context.getSharedPreferences("im.vector.matrix.android.realm", Context.MODE_PRIVATE)
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 caaf6b81100ce609bf37c09213522768f77db7b8..234caec970df92d5d201e0fdec4146615642d151 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
@@ -17,7 +17,6 @@
 package org.matrix.android.sdk.internal.database.helper
 
 import io.realm.Realm
-import io.realm.Sort
 import io.realm.kotlin.createObject
 import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
 import org.matrix.android.sdk.internal.database.model.ChunkEntity
@@ -34,32 +33,9 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
 import org.matrix.android.sdk.internal.database.query.find
 import org.matrix.android.sdk.internal.database.query.getOrCreate
 import org.matrix.android.sdk.internal.database.query.where
-import org.matrix.android.sdk.internal.database.query.whereRoomId
-import org.matrix.android.sdk.internal.extensions.assertIsManaged
 import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
 import timber.log.Timber
 
-internal fun ChunkEntity.merge(roomId: String, chunkToMerge: ChunkEntity, direction: PaginationDirection) {
-    assertIsManaged()
-    val localRealm = this.realm
-    val eventsToMerge: List<TimelineEventEntity>
-    if (direction == PaginationDirection.FORWARDS) {
-        this.nextToken = chunkToMerge.nextToken
-        this.isLastForward = chunkToMerge.isLastForward
-        eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING)
-    } else {
-        this.prevToken = chunkToMerge.prevToken
-        this.isLastBackward = chunkToMerge.isLastBackward
-        eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)
-    }
-    chunkToMerge.stateEvents.forEach { stateEvent ->
-        addStateEvent(roomId, stateEvent, direction)
-    }
-    eventsToMerge.forEach {
-        addTimelineEventFromMerge(localRealm, it, direction)
-    }
-}
-
 internal fun ChunkEntity.addStateEvent(roomId: String, stateEvent: EventEntity, direction: PaginationDirection) {
     if (direction == PaginationDirection.BACKWARDS) {
         Timber.v("We don't keep chunk state events when paginating backward")
@@ -79,11 +55,13 @@ internal fun ChunkEntity.addStateEvent(roomId: String, stateEvent: EventEntity,
     }
 }
 
-internal fun ChunkEntity.addTimelineEvent(roomId: String,
-                                          eventEntity: EventEntity,
-                                          direction: PaginationDirection,
-                                          ownedByThreadChunk: Boolean = false,
-                                          roomMemberContentsByUser: Map<String, RoomMemberContent?>? = null): TimelineEventEntity? {
+internal fun ChunkEntity.addTimelineEvent(
+        roomId: String,
+        eventEntity: EventEntity,
+        direction: PaginationDirection,
+        ownedByThreadChunk: Boolean = false,
+        roomMemberContentsByUser: Map<String, RoomMemberContent?>? = null
+): TimelineEventEntity? {
     val eventId = eventEntity.eventId
     if (timelineEvents.find(eventId) != null) {
         return null
@@ -142,40 +120,6 @@ internal fun computeIsUnique(
     }
 }
 
-private fun ChunkEntity.addTimelineEventFromMerge(realm: Realm, timelineEventEntity: TimelineEventEntity, direction: PaginationDirection) {
-    val eventId = timelineEventEntity.eventId
-    if (timelineEvents.find(eventId) != null) {
-        return
-    }
-    val displayIndex = nextDisplayIndex(direction)
-    val localId = TimelineEventEntity.nextId(realm)
-    val copied = realm.createObject<TimelineEventEntity>().apply {
-        this.localId = localId
-        this.root = timelineEventEntity.root
-        this.eventId = timelineEventEntity.eventId
-        this.roomId = timelineEventEntity.roomId
-        this.annotations = timelineEventEntity.annotations
-        this.readReceipts = timelineEventEntity.readReceipts
-        this.displayIndex = displayIndex
-        this.senderAvatar = timelineEventEntity.senderAvatar
-        this.senderName = timelineEventEntity.senderName
-        this.isUniqueDisplayName = timelineEventEntity.isUniqueDisplayName
-    }
-    handleThreadSummary(realm, eventId, copied)
-    timelineEvents.add(copied)
-}
-
-/**
- * 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
-            .whereRoomId(realm, newTimelineEventEntity.roomId)
-            .equalTo(EventEntityFields.IS_ROOT_THREAD, true)
-            .equalTo(EventEntityFields.THREAD_SUMMARY_LATEST_MESSAGE.EVENT_ID, oldEventId)
-            .findFirst()?.threadSummaryLatestMessage = newTimelineEventEntity
-}
-
 private fun handleReadReceipts(realm: Realm, roomId: String, eventEntity: EventEntity, senderId: String): ReadReceiptsSummaryEntity {
     val readReceiptsSummaryEntity = ReadReceiptsSummaryEntity.where(realm, eventEntity.eventId).findFirst()
             ?: realm.createObject<ReadReceiptsSummaryEntity>(eventEntity.eventId).apply {
@@ -199,7 +143,7 @@ private fun handleReadReceipts(realm: Realm, roomId: String, eventEntity: EventE
 
 internal fun ChunkEntity.nextDisplayIndex(direction: PaginationDirection): Int {
     return when (direction) {
-        PaginationDirection.FORWARDS  -> {
+        PaginationDirection.FORWARDS -> {
             (timelineEvents.where().max(TimelineEventEntityFields.DISPLAY_INDEX)?.toInt() ?: 0) + 1
         }
         PaginationDirection.BACKWARDS -> {
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 db3647c3fae24312b899091329e4a7c4b7aea074..dfac7f670878aa1cfa298809395022f1032f6576 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
@@ -47,9 +47,11 @@ private typealias Summary = Pair<Int, TimelineEventEntity>?
  */
 internal fun Map<String, EventEntity>.updateThreadSummaryIfNeeded(
         roomId: String,
-        realm: Realm, currentUserId: String,
+        realm: Realm,
+        currentUserId: String,
         chunkEntity: ChunkEntity? = null,
-        shouldUpdateNotifications: Boolean = true) {
+        shouldUpdateNotifications: Boolean = true
+) {
     for ((rootThreadEventId, eventEntity) in this) {
         eventEntity.threadSummaryInThread(eventEntity.realm, rootThreadEventId, chunkEntity)?.let { threadSummary ->
 
@@ -87,7 +89,8 @@ internal fun EventEntity.findRootThreadEvent(): EventEntity? =
  */
 internal fun EventEntity.markEventAsRoot(
         inThreadMessages: Int,
-        latestMessageTimelineEventEntity: TimelineEventEntity?) {
+        latestMessageTimelineEventEntity: TimelineEventEntity?
+) {
     isRootThread = true
     numberOfThreads = inThreadMessages
     threadSummaryLatestMessage = latestMessageTimelineEventEntity
@@ -96,7 +99,9 @@ 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.
+ * @param realm the realm database
  * @param rootThreadEventId The root eventId that will find the number of threads
+ * @param chunkEntity the chunk entity
  * @return A ThreadSummary containing the counted threads and the latest event message
  */
 internal fun EventEntity.threadSummaryInThread(realm: Realm, rootThreadEventId: String, chunkEntity: ChunkEntity?): Summary {
@@ -184,6 +189,7 @@ private fun findLatestSortedChunkEvent(chunk: ChunkEntity, rootThreadEventId: St
 
 /**
  * Find all TimelineEventEntity that are root threads for the specified room.
+ * @param realm the realm instance
  * @param roomId The room that all stored root threads will be returned
  */
 internal fun TimelineEventEntity.Companion.findAllThreadsForRoomId(realm: Realm, roomId: String): RealmQuery<TimelineEventEntity> =
@@ -218,6 +224,7 @@ internal fun List<TimelineEvent>.mapEventsWithEdition(realm: Realm, roomId: Stri
 
 /**
  * Returns a list of all the marked unread threads that exists for the specified room.
+ * @param realm the realm instance
  * @param roomId The roomId that the user is currently in
  */
 internal fun TimelineEventEntity.Companion.findAllLocalThreadNotificationsForRoomId(realm: Realm, roomId: String): RealmQuery<TimelineEventEntity> =
@@ -232,6 +239,7 @@ internal fun TimelineEventEntity.Companion.findAllLocalThreadNotificationsForRoo
 
 /**
  * Returns whether or not the given user is participating in a current thread.
+ * @param realm the realm instance
  * @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
@@ -247,6 +255,7 @@ internal fun TimelineEventEntity.Companion.isUserParticipatingInThread(realm: Re
 
 /**
  * Returns whether or not the given user is mentioned in a current thread.
+ * @param realm the realm instance
  * @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
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 3bf574c207db20f12d2949e2398426834e39b704..79a99cdfac4c282d5d9877fed8ba7278a930ab59 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
@@ -54,7 +54,8 @@ internal fun ThreadSummaryEntity.updateThreadSummary(
         numberOfThreads: Int?,
         latestThreadEventEntity: EventEntity?,
         isUserParticipating: Boolean,
-        roomMemberContentsByUser: HashMap<String, RoomMemberContent?>) {
+        roomMemberContentsByUser: HashMap<String, RoomMemberContent?>
+) {
     updateThreadSummaryRootEvent(rootThreadEventEntity, roomMemberContentsByUser)
     updateThreadSummaryLatestEvent(latestThreadEventEntity, roomMemberContentsByUser)
     this.isUserParticipating = isUserParticipating
@@ -180,7 +181,7 @@ internal fun ThreadSummaryEntity.Companion.createOrUpdate(
 
             roomEntity.addIfNecessary(threadSummary)
         }
-        ThreadSummaryUpdateType.ADD     -> {
+        ThreadSummaryUpdateType.ADD -> {
             val rootThreadEventId = threadEventEntity?.rootThreadEventId ?: return
             Timber.i("###THREADS ThreadSummaryHelper ADD for root eventId:$rootThreadEventId")
 
@@ -303,6 +304,7 @@ private fun getLatestEvent(rootThreadEvent: Event): 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.
+ * @param realm the realm instance
  * @param roomId The id of the room
  */
 internal fun ThreadSummaryEntity.Companion.findAllThreadsForRoomId(realm: Realm, roomId: String): RealmQuery<ThreadSummaryEntity> =
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 a00a2a8ee111d189741323704b23a465d0d2abd7..4cf2ef6723ed0518107ace1bc0255f71a1cb4304 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
@@ -27,21 +27,21 @@ internal object DraftMapper {
     fun map(entity: DraftEntity): UserDraft {
         return when (entity.draftMode) {
             DraftEntity.MODE_REGULAR -> UserDraft.Regular(entity.content)
-            DraftEntity.MODE_EDIT    -> UserDraft.Edit(entity.linkedEventId, entity.content)
-            DraftEntity.MODE_QUOTE   -> UserDraft.Quote(entity.linkedEventId, entity.content)
-            DraftEntity.MODE_REPLY   -> UserDraft.Reply(entity.linkedEventId, entity.content)
-            DraftEntity.MODE_VOICE   -> UserDraft.Voice(entity.content)
-            else                     -> null
+            DraftEntity.MODE_EDIT -> UserDraft.Edit(entity.linkedEventId, entity.content)
+            DraftEntity.MODE_QUOTE -> UserDraft.Quote(entity.linkedEventId, entity.content)
+            DraftEntity.MODE_REPLY -> UserDraft.Reply(entity.linkedEventId, entity.content)
+            DraftEntity.MODE_VOICE -> UserDraft.Voice(entity.content)
+            else -> null
         } ?: UserDraft.Regular("")
     }
 
     fun map(domain: UserDraft): DraftEntity {
         return when (domain) {
             is UserDraft.Regular -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_REGULAR, linkedEventId = "")
-            is UserDraft.Edit    -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_EDIT, linkedEventId = domain.linkedEventId)
-            is UserDraft.Quote   -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_QUOTE, linkedEventId = domain.linkedEventId)
-            is UserDraft.Reply   -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_REPLY, linkedEventId = domain.linkedEventId)
-            is UserDraft.Voice   -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_VOICE, linkedEventId = "")
+            is UserDraft.Edit -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_EDIT, linkedEventId = domain.linkedEventId)
+            is UserDraft.Quote -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_QUOTE, linkedEventId = domain.linkedEventId)
+            is UserDraft.Reply -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_REPLY, linkedEventId = domain.linkedEventId)
+            is UserDraft.Voice -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_VOICE, linkedEventId = "")
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt
index c747ad334fee19ff858b40b69edfe901149b6236..6bbeb17fdd021af5a9a9123c01e946999d95320e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt
@@ -58,7 +58,7 @@ internal object EventAnnotationsSummaryMapper {
                     PollResponseAggregatedSummaryEntityMapper.map(it)
                 },
                 liveLocationShareAggregatedSummary = annotationsSummary.liveLocationShareAggregatedSummary?.let {
-                    LiveLocationShareAggregatedSummaryMapper.map(it)
+                    LiveLocationShareAggregatedSummaryMapper().map(it)
                 }
         )
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt
index bc7d40bf6f1dcec8977063f41d4b92197d8ce9aa..5b60c536425155562f3cfad3528e5a3793eb9f7b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt
@@ -127,10 +127,12 @@ internal fun EventEntity.asDomain(castJsonNumbers: Boolean = false): Event {
     return EventMapper.map(this, castJsonNumbers)
 }
 
-internal fun Event.toEntity(roomId: String,
-                            sendState: SendState,
-                            ageLocalTs: Long?,
-                            contentToInject: String? = null): EventEntity {
+internal fun Event.toEntity(
+        roomId: String,
+        sendState: SendState,
+        ageLocalTs: Long?,
+        contentToInject: String? = null
+): EventEntity {
     return EventMapper.map(this, roomId).apply {
         this.sendState = sendState
         this.ageLocalTs = ageLocalTs
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/IsUselessResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/IsUselessResolver.kt
index d704ecac8e0a61fa65905dc95c110587b605235e..1a4821e80c53f6d503d36dcac213634995d828a7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/IsUselessResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/IsUselessResolver.kt
@@ -32,7 +32,7 @@ internal object IsUselessResolver {
                 event.content != null &&
                         event.content.toContent() == event.resolvedPrevContent()?.toContent()
             }
-            else                        -> false
+            else -> false
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt
index 71b36f88bd8f30a60f01c2e8655e094850a80de4..9460e4c6ba228a5264826819c88fc9e760b2d349 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt
@@ -20,11 +20,13 @@ import org.matrix.android.sdk.api.session.events.model.toModel
 import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
 import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
 import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
+import javax.inject.Inject
 
-internal object LiveLocationShareAggregatedSummaryMapper {
+internal class LiveLocationShareAggregatedSummaryMapper @Inject constructor() {
 
     fun map(entity: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary {
         return LiveLocationShareAggregatedSummary(
+                userId = entity.userId,
                 isActive = entity.isActive,
                 endOfLiveTimestampMillis = entity.endOfLiveTimestampMillis,
                 lastLocationDataContent = ContentMapper.map(entity.lastLocationContent).toModel<MessageBeaconLocationDataContent>()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt
index 41faf30a82e726c56290521151b7e8ce2a7ce811..735cfe411ce67b2b695652b3fd35e5dc78b93cf5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt
@@ -29,8 +29,10 @@ import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
 import org.matrix.android.sdk.internal.database.model.presence.toUserPresence
 import javax.inject.Inject
 
-internal class RoomSummaryMapper @Inject constructor(private val timelineEventMapper: TimelineEventMapper,
-                                                     private val typingUsersTracker: TypingUsersTracker) {
+internal class RoomSummaryMapper @Inject constructor(
+        private val timelineEventMapper: TimelineEventMapper,
+        private val typingUsersTracker: TypingUsersTracker
+) {
 
     fun map(roomSummaryEntity: RoomSummaryEntity): RoomSummary {
         val tags = roomSummaryEntity.tags().map {
@@ -109,7 +111,7 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
                     // I should probably use #hasEncryptorClassForAlgorithm but it says it supports
                     // OLM which is some legacy? Now only megolm allowed in rooms
                     MXCRYPTO_ALGORITHM_MEGOLM -> RoomEncryptionAlgorithm.Megolm
-                    else                      -> RoomEncryptionAlgorithm.UnsupportedAlgorithm(alg)
+                    else -> RoomEncryptionAlgorithm.UnsupportedAlgorithm(alg)
                 }
         )
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo019.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo019.kt
index 754a66bb4b9de9059aa0fadc98e8c010a57acdd8..38de70cc7ca1ec487417ec8d099a09962d2161d0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo019.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo019.kt
@@ -21,8 +21,10 @@ import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
 import org.matrix.android.sdk.internal.util.Normalizer
 import org.matrix.android.sdk.internal.util.database.RealmMigrator
 
-internal class MigrateSessionTo019(realm: DynamicRealm,
-                                   private val normalizer: Normalizer) : RealmMigrator(realm, 19) {
+internal class MigrateSessionTo019(
+        realm: DynamicRealm,
+        private val normalizer: Normalizer
+) : RealmMigrator(realm, 19) {
 
     override fun doMigrate(realm: DynamicRealm) {
         realm.schema.get("RoomSummaryEntity")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt
new file mode 100644
index 0000000000000000000000000000000000000000..aebca11c2bb3b409057d09de82dbe8d508d42604
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.database.migration
+
+import io.realm.DynamicRealm
+import io.realm.FieldAttribute
+import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+
+/**
+ * Migrating to:
+ * Live location sharing aggregated summary: adding new field userId.
+ */
+internal class MigrateSessionTo029(realm: DynamicRealm) : RealmMigrator(realm, 28) {
+
+    override fun doMigrate(realm: DynamicRealm) {
+        realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
+                ?.addField(LiveLocationShareAggregatedSummaryEntityFields.USER_ID, String::class.java, FieldAttribute.REQUIRED)
+                ?.transform { obj ->
+                    obj.setString(LiveLocationShareAggregatedSummaryEntityFields.USER_ID, "")
+                }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo030.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo030.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b9c611f5dde8c0d209229c60a3b8ba70759e3554
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo030.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.database.migration
+
+import io.realm.DynamicRealm
+import org.matrix.android.sdk.internal.database.model.ChunkEntityFields
+import org.matrix.android.sdk.internal.database.model.EventEntityFields
+import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
+import org.matrix.android.sdk.internal.util.database.RealmMigrator
+import timber.log.Timber
+
+/**
+ * Migrating to:
+ * Cleaning old chunks which may have broken links.
+ */
+internal class MigrateSessionTo030(realm: DynamicRealm) : RealmMigrator(realm, 30) {
+
+    override fun doMigrate(realm: DynamicRealm) {
+        // Delete all previous chunks
+        val chunks = realm.where("ChunkEntity")
+                .equalTo(ChunkEntityFields.IS_LAST_FORWARD, false)
+                .findAll()
+
+        val nbOfDeletedChunks = chunks.size
+        var nbOfDeletedTimelineEvents = 0
+        var nbOfDeletedEvents = 0
+        chunks.forEach { chunk ->
+            val timelineEvents = chunk.getList(ChunkEntityFields.TIMELINE_EVENTS.`$`)
+            timelineEvents.forEach { timelineEvent ->
+                // Don't delete state events
+                val event = timelineEvent.getObject(TimelineEventEntityFields.ROOT.`$`)
+                if (event?.isNull(EventEntityFields.STATE_KEY) == true) {
+                    nbOfDeletedEvents++
+                    event.deleteFromRealm()
+                }
+            }
+            nbOfDeletedTimelineEvents += timelineEvents.size
+            timelineEvents.deleteAllFromRealm()
+        }
+        chunks.deleteAllFromRealm()
+        Timber.d("MigrateSessionTo030: $nbOfDeletedChunks deleted chunk(s), $nbOfDeletedTimelineEvents deleted TimelineEvent(s) and $nbOfDeletedEvents deleted Event(s).")
+    }
+}
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 8399d82d5d75821e55d769dd8c8d06baca2be775..e5360ce0b63c66a154e07b9be116aba10518e4c9 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
@@ -53,7 +53,8 @@ internal open class ChunkEntity(
 
 internal fun ChunkEntity.deleteOnCascade(
         deleteStateEvents: Boolean,
-        canDeleteRoot: Boolean) {
+        canDeleteRoot: Boolean
+) {
     assertIsManaged()
     if (deleteStateEvents) {
         stateEvents.deleteAllFromRealm()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/CurrentStateEventEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/CurrentStateEventEntity.kt
index 251b05772290da9491245b092eef029ae6fdde3c..9deef69dabaa5a02d37342cf3d94fa444c91a78f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/CurrentStateEventEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/CurrentStateEventEntity.kt
@@ -20,11 +20,12 @@ package org.matrix.android.sdk.internal.database.model
 import io.realm.RealmObject
 import io.realm.annotations.Index
 
-internal open class CurrentStateEventEntity(var eventId: String = "",
-                                            var root: EventEntity? = null,
-                                            @Index var roomId: String = "",
-                                            @Index var type: String = "",
-                                            @Index var stateKey: String = ""
+internal open class CurrentStateEventEntity(
+        var eventId: String = "",
+        var root: EventEntity? = null,
+        @Index var roomId: String = "",
+        @Index var type: String = "",
+        @Index var stateKey: String = ""
 ) : RealmObject() {
     companion object
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/DraftEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/DraftEntity.kt
index fd09da4448f61341c391d1ad2d42576cc38b57af..3c19d4d4435f2e75c64827572bbac0144499e1f5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/DraftEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/DraftEntity.kt
@@ -18,9 +18,10 @@ package org.matrix.android.sdk.internal.database.model
 
 import io.realm.RealmObject
 
-internal open class DraftEntity(var content: String = "",
-                                var draftMode: String = MODE_REGULAR,
-                                var linkedEventId: String = ""
+internal open class DraftEntity(
+        var content: String = "",
+        var draftMode: String = MODE_REGULAR,
+        var linkedEventId: String = ""
 ) : RealmObject() {
 
     companion object {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt
index ba80cc8302aec1d0da5568e7bc2edd67a667111e..8b5a211fbaba4d5a477baff5aec881a48f047765 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt
@@ -25,28 +25,29 @@ import org.matrix.android.sdk.api.session.threads.ThreadNotificationState
 import org.matrix.android.sdk.internal.di.MoshiProvider
 import org.matrix.android.sdk.internal.extensions.assertIsManaged
 
-internal open class EventEntity(@Index var eventId: String = "",
-                                @Index var roomId: String = "",
-                                @Index var type: String = "",
-                                var content: String? = null,
-                                var prevContent: String? = null,
-                                var isUseless: Boolean = false,
-                                @Index var stateKey: String? = null,
-                                var originServerTs: Long? = null,
-                                @Index var sender: String? = null,
+internal open class EventEntity(
+        @Index var eventId: String = "",
+        @Index var roomId: String = "",
+        @Index var type: String = "",
+        var content: String? = null,
+        var prevContent: String? = null,
+        var isUseless: Boolean = false,
+        @Index var stateKey: String? = null,
+        var originServerTs: Long? = null,
+        @Index var sender: String? = null,
         // Can contain a serialized MatrixError
-                                var sendStateDetails: String? = null,
-                                var age: Long? = 0,
-                                var unsignedData: String? = null,
-                                var redacts: String? = null,
-                                var decryptionResultJson: String? = null,
-                                var ageLocalTs: Long? = null,
+        var sendStateDetails: String? = null,
+        var age: Long? = 0,
+        var unsignedData: String? = null,
+        var redacts: String? = null,
+        var decryptionResultJson: String? = null,
+        var ageLocalTs: Long? = null,
         // Thread related, no need to create a new Entity for performance
-                                @Index var isRootThread: Boolean = false,
-                                @Index var rootThreadEventId: String? = null,
+        @Index var isRootThread: Boolean = false,
+        @Index var rootThreadEventId: String? = null,
         // Number messages within the thread
-                                var numberOfThreads: Int = 0,
-                                var threadSummaryLatestMessage: TimelineEventEntity? = null
+        var numberOfThreads: Int = 0,
+        var threadSummaryLatestMessage: TimelineEventEntity? = null
 ) : RealmObject() {
 
     private var sendStateStr: String = SendState.UNKNOWN.name
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventInsertEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventInsertEntity.kt
index 5cfd306d2f0fab6b4822c0dc2f47b3237cbe646c..eff332dc3a9916724c927a50109291afe19a64a3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventInsertEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventInsertEntity.kt
@@ -22,13 +22,14 @@ import io.realm.RealmObject
  * This class is used to get notification on new events being inserted. It's to avoid realm getting slow when listening to insert
  * in EventEntity table.
  */
-internal open class EventInsertEntity(var eventId: String = "",
-                                      var eventType: String = "",
-                                      /**
-                                       * This flag will be used to filter EventInsertEntity in EventInsertLiveObserver.
-                                       * Currently it's set to false when the event content is encrypted.
-                                       */
-                                      var canBeProcessed: Boolean = true
+internal open class EventInsertEntity(
+        var eventId: String = "",
+        var eventType: String = "",
+        /**
+         * This flag will be used to filter EventInsertEntity in EventInsertLiveObserver.
+         * Currently it's set to false when the event content is encrypted.
+         */
+        var canBeProcessed: Boolean = true
 ) : RealmObject() {
 
     private var insertTypeStr: String = EventInsertType.INCREMENTAL_SYNC.name
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupSummaryEntity.kt
index 4ba45dcda2d19ef3df08e5223140891b00216410..d96514855976cf05b19a1b87534fdc742f4bd83f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupSummaryEntity.kt
@@ -21,12 +21,13 @@ import io.realm.RealmObject
 import io.realm.annotations.PrimaryKey
 import org.matrix.android.sdk.api.session.room.model.Membership
 
-internal open class GroupSummaryEntity(@PrimaryKey var groupId: String = "",
-                                       var displayName: String = "",
-                                       var shortDescription: String = "",
-                                       var avatarUrl: String = "",
-                                       var roomIds: RealmList<String> = RealmList(),
-                                       var userIds: RealmList<String> = RealmList()
+internal open class GroupSummaryEntity(
+        @PrimaryKey var groupId: String = "",
+        var displayName: String = "",
+        var shortDescription: String = "",
+        var avatarUrl: String = "",
+        var roomIds: RealmList<String> = RealmList(),
+        var userIds: RealmList<String> = RealmList()
 ) : RealmObject() {
 
     private var membershipStr: String = Membership.NONE.name
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ReadReceiptEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ReadReceiptEntity.kt
index e01d849cc22563c1d9dd74199dd6505fb7ff04be..9623c95359718f81dd994a17573baa6d7b310015 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ReadReceiptEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ReadReceiptEntity.kt
@@ -21,11 +21,12 @@ import io.realm.RealmResults
 import io.realm.annotations.LinkingObjects
 import io.realm.annotations.PrimaryKey
 
-internal open class ReadReceiptEntity(@PrimaryKey var primaryKey: String = "",
-                                      var eventId: String = "",
-                                      var roomId: String = "",
-                                      var userId: String = "",
-                                      var originServerTs: Double = 0.0
+internal open class ReadReceiptEntity(
+        @PrimaryKey var primaryKey: String = "",
+        var eventId: String = "",
+        var roomId: String = "",
+        var userId: String = "",
+        var originServerTs: Double = 0.0
 ) : RealmObject() {
     companion object
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt
index d8e6b8af0faaa0fcc22562b10ec993bb6f01903c..d2116fa9b89ad8369dc0bb8eb996fd60004fdd3e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt
@@ -24,11 +24,12 @@ import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntit
 import org.matrix.android.sdk.internal.database.query.findRootOrLatest
 import org.matrix.android.sdk.internal.extensions.assertIsManaged
 
-internal open class RoomEntity(@PrimaryKey var roomId: String = "",
-                               var chunks: RealmList<ChunkEntity> = RealmList(),
-                               var sendingTimelineEvents: RealmList<TimelineEventEntity> = RealmList(),
-                               var threadSummaries: RealmList<ThreadSummaryEntity> = RealmList(),
-                               var accountData: RealmList<RoomAccountDataEntity> = RealmList()
+internal open class RoomEntity(
+        @PrimaryKey var roomId: String = "",
+        var chunks: RealmList<ChunkEntity> = RealmList(),
+        var sendingTimelineEvents: RealmList<TimelineEventEntity> = RealmList(),
+        var threadSummaries: RealmList<ThreadSummaryEntity> = RealmList(),
+        var accountData: RealmList<RoomAccountDataEntity> = RealmList()
 ) : RealmObject() {
 
     private var membershipStr: String = Membership.NONE.name
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomMemberSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomMemberSummaryEntity.kt
index a8a76d16811f661fcbf4f2ce2bbc9b8a9a43aa33..6fb9324fcd8c7e2b2ed77a30678ca40e2b418c9a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomMemberSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomMemberSummaryEntity.kt
@@ -23,13 +23,14 @@ import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.util.MatrixItem
 import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntity
 
-internal open class RoomMemberSummaryEntity(@PrimaryKey var primaryKey: String = "",
-                                            @Index var userId: String = "",
-                                            @Index var roomId: String = "",
-                                            @Index var displayName: String? = null,
-                                            var avatarUrl: String? = null,
-                                            var reason: String? = null,
-                                            var isDirect: Boolean = false
+internal open class RoomMemberSummaryEntity(
+        @PrimaryKey var primaryKey: String = "",
+        @Index var userId: String = "",
+        @Index var roomId: String = "",
+        @Index var displayName: String? = null,
+        var avatarUrl: String? = null,
+        var reason: String? = null,
+        var isDirect: Boolean = false
 ) : RealmObject() {
 
     private var membershipStr: String = Membership.NONE.name
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SyncEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SyncEntity.kt
index a82ec41456b7f297bb7ab454458b0ec67643e614..ff261b80c19e1973526de0866cbded4236e83f94 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SyncEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SyncEntity.kt
@@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.database.model
 import io.realm.RealmObject
 import io.realm.annotations.PrimaryKey
 
-internal open class SyncEntity(var nextBatch: String? = null,
-                               @PrimaryKey var id: Long = 0
+internal open class SyncEntity(
+        var nextBatch: String? = null,
+        @PrimaryKey var id: Long = 0
 ) : RealmObject()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/TimelineEventEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/TimelineEventEntity.kt
index 477c04fe518097b6aef604a9214b09ab52337cf8..c8f22dc2ccbe8950907c48a470b7f8223e5bd009 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/TimelineEventEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/TimelineEventEntity.kt
@@ -22,20 +22,21 @@ import io.realm.annotations.Index
 import io.realm.annotations.LinkingObjects
 import org.matrix.android.sdk.internal.extensions.assertIsManaged
 
-internal open class TimelineEventEntity(var localId: Long = 0,
-                                        @Index var eventId: String = "",
-                                        @Index var roomId: String = "",
-                                        @Index var displayIndex: Int = 0,
-                                        var root: EventEntity? = null,
-                                        var annotations: EventAnnotationsSummaryEntity? = null,
-                                        var senderName: String? = null,
-                                        var isUniqueDisplayName: Boolean = false,
-                                        var senderAvatar: String? = null,
-                                        var senderMembershipEventId: String? = null,
+internal open class TimelineEventEntity(
+        var localId: Long = 0,
+        @Index var eventId: String = "",
+        @Index var roomId: String = "",
+        @Index var displayIndex: Int = 0,
+        var root: EventEntity? = null,
+        var annotations: EventAnnotationsSummaryEntity? = null,
+        var senderName: String? = null,
+        var isUniqueDisplayName: Boolean = false,
+        var senderAvatar: String? = null,
+        var senderMembershipEventId: String? = null,
         // ownedByThreadChunk indicates that the current TimelineEventEntity belongs
         // to a thread chunk and is a temporarily event.
-                                        var ownedByThreadChunk: Boolean = false,
-                                        var readReceipts: ReadReceiptsSummaryEntity? = null
+        var ownedByThreadChunk: Boolean = false,
+        var readReceipts: ReadReceiptsSummaryEntity? = null
 ) : RealmObject() {
 
     @LinkingObjects("timelineEvents")
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 2c778f979762a31ca76788697bf1ff14a9d83d0f..7ccfc6b104e3f029ad08c85e239c4d29898d1802 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
@@ -24,7 +24,8 @@ import io.realm.annotations.LinkingObjects
 /**
  * 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()
+internal open class UserDraftsEntity(
+        var userDrafts: RealmList<DraftEntity> = RealmList()
 ) : RealmObject() {
 
     // Link to RoomSummaryEntity
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserEntity.kt
index bd6e73582d837d00e9e0349ad0ca495d739b8092..3644d12ac9f2389032cf16846f9bb8a409471b7d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserEntity.kt
@@ -19,9 +19,10 @@ package org.matrix.android.sdk.internal.database.model
 import io.realm.RealmObject
 import io.realm.annotations.PrimaryKey
 
-internal open class UserEntity(@PrimaryKey var userId: String = "",
-                               var displayName: String = "",
-                               var avatarUrl: String = ""
+internal open class UserEntity(
+        @PrimaryKey var userId: String = "",
+        var displayName: String = "",
+        var avatarUrl: String = ""
 ) : RealmObject() {
 
     companion object
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 4d0d2c5c64303cbbfc676c3ce419b3adcdc9e739..c5df8e933838d2eaf43b068aa9ccdac1405c662a 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
@@ -31,6 +31,11 @@ internal open class LiveLocationShareAggregatedSummaryEntity(
 
         var roomId: String = "",
 
+        var userId: String = "",
+
+        /**
+         * Indicate whether the live is currently running.
+         */
         var isActive: Boolean? = null,
 
         var endOfLiveTimestampMillis: Long? = null,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/presence/UserPresenceEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/presence/UserPresenceEntity.kt
index 5713337ec574fc9893ec2e91ee44ecca4259e9e8..8d808417c27e9bbf3f08bcd428e8e42bd167ce24 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/presence/UserPresenceEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/presence/UserPresenceEntity.kt
@@ -21,12 +21,13 @@ import io.realm.annotations.PrimaryKey
 import org.matrix.android.sdk.api.session.presence.model.PresenceEnum
 import org.matrix.android.sdk.api.session.presence.model.UserPresence
 
-internal open class UserPresenceEntity(@PrimaryKey var userId: String = "",
-                                       var lastActiveAgo: Long? = null,
-                                       var statusMessage: String? = null,
-                                       var isCurrentlyActive: Boolean? = null,
-                                       var avatarUrl: String? = null,
-                                       var displayName: String? = null
+internal open class UserPresenceEntity(
+        @PrimaryKey var userId: String = "",
+        var lastActiveAgo: Long? = null,
+        var statusMessage: String? = null,
+        var isCurrentlyActive: Boolean? = null,
+        var avatarUrl: String? = null,
+        var displayName: String? = null
 ) : RealmObject() {
 
     var presence: PresenceEnum
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/threads/ThreadSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/threads/ThreadSummaryEntity.kt
index ab9d66548ed418a47652a8f0f4944b084869c8aa..45f9e3aa209583959d20b964aab3bee87f6b3e3c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/threads/ThreadSummaryEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/threads/ThreadSummaryEntity.kt
@@ -23,17 +23,18 @@ import io.realm.annotations.LinkingObjects
 import org.matrix.android.sdk.internal.database.model.EventEntity
 import org.matrix.android.sdk.internal.database.model.RoomEntity
 
-internal open class ThreadSummaryEntity(@Index var rootThreadEventId: String? = "",
-                                        var rootThreadEventEntity: EventEntity? = null,
-                                        var latestThreadEventEntity: EventEntity? = null,
-                                        var rootThreadSenderName: String? = null,
-                                        var latestThreadSenderName: String? = null,
-                                        var rootThreadSenderAvatar: String? = null,
-                                        var latestThreadSenderAvatar: String? = null,
-                                        var rootThreadIsUniqueDisplayName: Boolean = false,
-                                        var isUserParticipating: Boolean = false,
-                                        var latestThreadIsUniqueDisplayName: Boolean = false,
-                                        var numberOfThreads: Int = 0
+internal open class ThreadSummaryEntity(
+        @Index var rootThreadEventId: String? = "",
+        var rootThreadEventEntity: EventEntity? = null,
+        var latestThreadEventEntity: EventEntity? = null,
+        var rootThreadSenderName: String? = null,
+        var latestThreadSenderName: String? = null,
+        var rootThreadSenderAvatar: String? = null,
+        var latestThreadSenderAvatar: String? = null,
+        var rootThreadIsUniqueDisplayName: Boolean = false,
+        var isUserParticipating: Boolean = false,
+        var latestThreadIsUniqueDisplayName: Boolean = false,
+        var numberOfThreads: Int = 0
 ) : RealmObject() {
 
     @LinkingObjects("threadSummaries")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt
index 9350102137042b6b35c6e94762143f9c07da0914..1e5d96b4964f4246045428aa7ca6a97e1c1af999 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt
@@ -31,6 +31,7 @@ internal fun ChunkEntity.Companion.where(realm: Realm, roomId: String): RealmQue
 
 internal fun ChunkEntity.Companion.find(realm: Realm, roomId: String, prevToken: String? = null, nextToken: String? = null): ChunkEntity? {
     val query = where(realm, roomId)
+    if (prevToken == null && nextToken == null) return null
     if (prevToken != null) {
         query.equalTo(ChunkEntityFields.PREV_TOKEN, prevToken)
     }
@@ -40,7 +41,7 @@ internal fun ChunkEntity.Companion.find(realm: Realm, roomId: String, prevToken:
     return query.findFirst()
 }
 
-internal fun ChunkEntity.Companion.findAll(realm: Realm, roomId: String, prevToken: String? = null, nextToken: String? = null): RealmResults<ChunkEntity>? {
+internal fun ChunkEntity.Companion.findAll(realm: Realm, roomId: String, prevToken: String? = null, nextToken: String? = null): RealmResults<ChunkEntity> {
     val query = where(realm, roomId)
     if (prevToken != null) {
         query.equalTo(ChunkEntityFields.PREV_TOKEN, prevToken)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/CurrentStateEventEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/CurrentStateEventEntityQueries.kt
index 716783f2bab70d0fc06889c4416c2f5153904271..e0dbf2eee82cb7baf4e3c2909093ed015534ee9e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/CurrentStateEventEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/CurrentStateEventEntityQueries.kt
@@ -23,40 +23,50 @@ import io.realm.kotlin.createObject
 import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
 import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
 
-internal fun CurrentStateEventEntity.Companion.whereType(realm: Realm,
-                                                         roomId: String,
-                                                         type: String): RealmQuery<CurrentStateEventEntity> {
+internal fun CurrentStateEventEntity.Companion.whereType(
+        realm: Realm,
+        roomId: String,
+        type: String
+): RealmQuery<CurrentStateEventEntity> {
     return realm.where(CurrentStateEventEntity::class.java)
             .equalTo(CurrentStateEventEntityFields.ROOM_ID, roomId)
             .equalTo(CurrentStateEventEntityFields.TYPE, type)
 }
 
-internal fun CurrentStateEventEntity.Companion.whereStateKey(realm: Realm,
-                                                             roomId: String,
-                                                             type: String,
-                                                             stateKey: String): RealmQuery<CurrentStateEventEntity> {
+internal fun CurrentStateEventEntity.Companion.whereStateKey(
+        realm: Realm,
+        roomId: String,
+        type: String,
+        stateKey: String
+): RealmQuery<CurrentStateEventEntity> {
     return whereType(realm = realm, roomId = roomId, type = type)
             .equalTo(CurrentStateEventEntityFields.STATE_KEY, stateKey)
 }
 
-internal fun CurrentStateEventEntity.Companion.getOrNull(realm: Realm,
-                                                         roomId: String,
-                                                         stateKey: String,
-                                                         type: String): CurrentStateEventEntity? {
+internal fun CurrentStateEventEntity.Companion.getOrNull(
+        realm: Realm,
+        roomId: String,
+        stateKey: String,
+        type: String
+): CurrentStateEventEntity? {
     return whereStateKey(realm = realm, roomId = roomId, type = type, stateKey = stateKey).findFirst()
 }
 
-internal fun CurrentStateEventEntity.Companion.getOrCreate(realm: Realm,
-                                                           roomId: String,
-                                                           stateKey: String,
-                                                           type: String): CurrentStateEventEntity {
+internal fun CurrentStateEventEntity.Companion.getOrCreate(
+        realm: Realm,
+        roomId: String,
+        stateKey: String,
+        type: String
+): CurrentStateEventEntity {
     return getOrNull(realm = realm, roomId = roomId, stateKey = stateKey, type = type) ?: create(realm, roomId, stateKey, type)
 }
 
-private fun create(realm: Realm,
-                   roomId: String,
-                   stateKey: String,
-                   type: String): CurrentStateEventEntity {
+private fun create(
+        realm: Realm,
+        roomId: String,
+        stateKey: String,
+        type: String
+): CurrentStateEventEntity {
     return realm.createObject<CurrentStateEventEntity>().apply {
         this.type = type
         this.roomId = roomId
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventEntityQueries.kt
index f7fa1037ba59687e450c5667cf5b2dcc3a714319..0f1c22604410134afe3083dd64ebbeefff36aa4e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventEntityQueries.kt
@@ -59,9 +59,10 @@ internal fun EventEntity.Companion.where(realm: Realm, eventIds: List<String>):
             .`in`(EventEntityFields.EVENT_ID, eventIds.toTypedArray())
 }
 
-internal fun EventEntity.Companion.whereType(realm: Realm,
-                                             type: String,
-                                             roomId: String? = null
+internal fun EventEntity.Companion.whereType(
+        realm: Realm,
+        type: String,
+        roomId: String? = null
 ): RealmQuery<EventEntity> {
     val query = realm.where<EventEntity>()
     if (roomId != null) {
@@ -70,9 +71,11 @@ internal fun EventEntity.Companion.whereType(realm: Realm,
     return query.equalTo(EventEntityFields.TYPE, type)
 }
 
-internal fun EventEntity.Companion.whereTypes(realm: Realm,
-                                              typeList: List<String> = emptyList(),
-                                              roomId: String? = null): RealmQuery<EventEntity> {
+internal fun EventEntity.Companion.whereTypes(
+        realm: Realm,
+        typeList: List<String> = emptyList(),
+        roomId: String? = null
+): RealmQuery<EventEntity> {
     val query = realm.where<EventEntity>()
     query.`in`(EventEntityFields.TYPE, typeList.toTypedArray())
     if (roomId != null) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LiveLocationShareAggregatedSummaryEntityQuery.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LiveLocationShareAggregatedSummaryEntityQuery.kt
index 2e2e939fa2003e29e12902e1255eedb591723928..7dfeb6884abf247224c8561a2e6ab6b8a7b2d743 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LiveLocationShareAggregatedSummaryEntityQuery.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LiveLocationShareAggregatedSummaryEntityQuery.kt
@@ -27,10 +27,18 @@ internal fun LiveLocationShareAggregatedSummaryEntity.Companion.where(
         realm: Realm,
         roomId: String,
         eventId: String,
+): RealmQuery<LiveLocationShareAggregatedSummaryEntity> {
+    return LiveLocationShareAggregatedSummaryEntity
+            .whereRoomId(realm, roomId = roomId)
+            .equalTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, eventId)
+}
+
+internal fun LiveLocationShareAggregatedSummaryEntity.Companion.whereRoomId(
+        realm: Realm,
+        roomId: String
 ): RealmQuery<LiveLocationShareAggregatedSummaryEntity> {
     return realm.where<LiveLocationShareAggregatedSummaryEntity>()
             .equalTo(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, roomId)
-            .equalTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, eventId)
 }
 
 internal fun LiveLocationShareAggregatedSummaryEntity.Companion.create(
@@ -55,3 +63,39 @@ internal fun LiveLocationShareAggregatedSummaryEntity.Companion.getOrCreate(
     return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).findFirst()
             ?: LiveLocationShareAggregatedSummaryEntity.create(realm, roomId, eventId)
 }
+
+internal fun LiveLocationShareAggregatedSummaryEntity.Companion.get(
+        realm: Realm,
+        roomId: String,
+        eventId: String,
+): LiveLocationShareAggregatedSummaryEntity? {
+    return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).findFirst()
+}
+
+internal fun LiveLocationShareAggregatedSummaryEntity.Companion.findActiveLiveInRoomForUser(
+        realm: Realm,
+        roomId: String,
+        userId: String,
+        ignoredEventId: String
+): List<LiveLocationShareAggregatedSummaryEntity> {
+    return LiveLocationShareAggregatedSummaryEntity
+            .whereRoomId(realm, roomId = roomId)
+            .equalTo(LiveLocationShareAggregatedSummaryEntityFields.USER_ID, userId)
+            .equalTo(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, true)
+            .notEqualTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, ignoredEventId)
+            .findAll()
+}
+
+/**
+ * A live is considered as running when active and with at least a last known location.
+ */
+internal fun LiveLocationShareAggregatedSummaryEntity.Companion.findRunningLiveInRoom(
+        realm: Realm,
+        roomId: String,
+): RealmQuery<LiveLocationShareAggregatedSummaryEntity> {
+    return LiveLocationShareAggregatedSummaryEntity
+            .whereRoomId(realm, roomId = roomId)
+            .equalTo(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, true)
+            .isNotEmpty(LiveLocationShareAggregatedSummaryEntityFields.USER_ID)
+            .isNotNull(LiveLocationShareAggregatedSummaryEntityFields.LAST_LOCATION_CONTENT)
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PushersQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PushersQueries.kt
index 3cea19a690f8d87e13bafb6a4b67b4c8d3559606..67fd8296d53b622ac6aa5ce44f0e16a41406af00 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PushersQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PushersQueries.kt
@@ -26,8 +26,10 @@ import org.matrix.android.sdk.internal.database.model.PushRulesEntityFields
 import org.matrix.android.sdk.internal.database.model.PusherEntity
 import org.matrix.android.sdk.internal.database.model.PusherEntityFields
 
-internal fun PusherEntity.Companion.where(realm: Realm,
-                                          pushKey: String? = null): RealmQuery<PusherEntity> {
+internal fun PusherEntity.Companion.where(
+        realm: Realm,
+        pushKey: String? = null
+): RealmQuery<PusherEntity> {
     return realm.where<PusherEntity>()
             .apply {
                 if (pushKey != null) {
@@ -36,17 +38,21 @@ internal fun PusherEntity.Companion.where(realm: Realm,
             }
 }
 
-internal fun PushRulesEntity.Companion.where(realm: Realm,
-                                             scope: String,
-                                             kind: RuleKind): RealmQuery<PushRulesEntity> {
+internal fun PushRulesEntity.Companion.where(
+        realm: Realm,
+        scope: String,
+        kind: RuleKind
+): RealmQuery<PushRulesEntity> {
     return realm.where<PushRulesEntity>()
             .equalTo(PushRulesEntityFields.SCOPE, scope)
             .equalTo(PushRulesEntityFields.KIND_STR, kind.name)
 }
 
-internal fun PushRuleEntity.Companion.where(realm: Realm,
-                                            scope: String,
-                                            ruleId: String): RealmQuery<PushRuleEntity> {
+internal fun PushRuleEntity.Companion.where(
+        realm: Realm,
+        scope: String,
+        ruleId: String
+): RealmQuery<PushRuleEntity> {
     return realm.where<PushRuleEntity>()
             .equalTo(PushRuleEntityFields.PARENT.SCOPE, scope)
             .equalTo(PushRuleEntityFields.RULE_ID, ruleId)
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 1a832a29bbbca135aa680e7b7e3d99a925d27266..0b0f01a67de8aff906bc081d8dc7b1f7bc5bec7c 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
@@ -24,10 +24,12 @@ import org.matrix.android.sdk.internal.database.model.ReadMarkerEntity
 import org.matrix.android.sdk.internal.database.model.ReadReceiptEntity
 import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
 
-internal fun isEventRead(realmConfiguration: RealmConfiguration,
-                         userId: String?,
-                         roomId: String?,
-                         eventId: String?): Boolean {
+internal fun isEventRead(
+        realmConfiguration: RealmConfiguration,
+        userId: String?,
+        roomId: String?,
+        eventId: String?
+): Boolean {
     if (userId.isNullOrBlank() || roomId.isNullOrBlank() || eventId.isNullOrBlank()) {
         return false
     }
@@ -39,12 +41,12 @@ internal fun isEventRead(realmConfiguration: RealmConfiguration,
         val eventToCheck = TimelineEventEntity.where(realm, roomId, eventId).findFirst()
         when {
             // The event doesn't exist locally, let's assume it hasn't been read
-            eventToCheck == null                                          -> false
-            eventToCheck.root?.sender == userId                           -> true
+            eventToCheck == null -> false
+            eventToCheck.root?.sender == userId -> true
             // If new event exists and the latest event is from ourselves we can infer the event is read
-            latestEventIsFromSelf(realm, roomId, userId)                  -> true
+            latestEventIsFromSelf(realm, roomId, userId) -> true
             eventToCheck.isBeforeLatestReadReceipt(realm, roomId, userId) -> true
-            else                                                          -> false
+            else -> false
         }
     }
 }
@@ -77,9 +79,11 @@ private fun Realm.hasReadReceiptInLatestChunk(latestChunkEntity: ChunkEntity, ro
     } != null
 }
 
-internal fun isReadMarkerMoreRecent(realmConfiguration: RealmConfiguration,
-                                    roomId: String?,
-                                    eventId: String?): Boolean {
+internal fun isReadMarkerMoreRecent(
+        realmConfiguration: RealmConfiguration,
+        roomId: String?,
+        eventId: String?
+): Boolean {
     if (roomId.isNullOrBlank() || eventId.isNullOrBlank()) {
         return false
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomSummaryEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomSummaryEntityQueries.kt
index 8993c36a300f1d41b7c510b2eb06d3e315ca9f1e..3c8d61432aa8f56a8331025af0475e7555c744b4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomSummaryEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomSummaryEntityQueries.kt
@@ -53,8 +53,10 @@ internal fun RoomSummaryEntity.Companion.getOrNull(realm: Realm, roomId: String)
     return where(realm, roomId).findFirst()
 }
 
-internal fun RoomSummaryEntity.Companion.getDirectRooms(realm: Realm,
-                                                        excludeRoomIds: Set<String>? = null): RealmResults<RoomSummaryEntity> {
+internal fun RoomSummaryEntity.Companion.getDirectRooms(
+        realm: Realm,
+        excludeRoomIds: Set<String>? = null
+): RealmResults<RoomSummaryEntity> {
     return RoomSummaryEntity.where(realm)
             .equalTo(RoomSummaryEntityFields.IS_DIRECT, true)
             .apply {
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 1654a33806dee20f2bf1f4bfa8c342f3fdd457b5..30010f90fd605213a08687f739b7df2722d65d5b 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
@@ -33,39 +33,49 @@ internal fun TimelineEventEntity.Companion.where(realm: Realm): RealmQuery<Timel
     return realm.where()
 }
 
-internal fun TimelineEventEntity.Companion.where(realm: Realm,
-                                                 roomId: String,
-                                                 eventId: String): RealmQuery<TimelineEventEntity> {
+internal fun TimelineEventEntity.Companion.where(
+        realm: Realm,
+        roomId: String,
+        eventId: String
+): RealmQuery<TimelineEventEntity> {
     return where(realm)
             .equalTo(TimelineEventEntityFields.ROOM_ID, roomId)
             .equalTo(TimelineEventEntityFields.EVENT_ID, eventId)
 }
 
-internal fun TimelineEventEntity.Companion.where(realm: Realm,
-                                                 roomId: String,
-                                                 eventIds: List<String>): RealmQuery<TimelineEventEntity> {
+internal fun TimelineEventEntity.Companion.where(
+        realm: Realm,
+        roomId: String,
+        eventIds: List<String>
+): RealmQuery<TimelineEventEntity> {
     return where(realm)
             .equalTo(TimelineEventEntityFields.ROOM_ID, roomId)
             .`in`(TimelineEventEntityFields.EVENT_ID, eventIds.toTypedArray())
 }
 
-internal fun TimelineEventEntity.Companion.whereRoomId(realm: Realm,
-                                                       roomId: String): RealmQuery<TimelineEventEntity> {
+internal fun TimelineEventEntity.Companion.whereRoomId(
+        realm: Realm,
+        roomId: String
+): RealmQuery<TimelineEventEntity> {
     return where(realm)
             .equalTo(TimelineEventEntityFields.ROOM_ID, roomId)
 }
 
-internal fun TimelineEventEntity.Companion.findWithSenderMembershipEvent(realm: Realm,
-                                                                         senderMembershipEventId: String): List<TimelineEventEntity> {
+internal fun TimelineEventEntity.Companion.findWithSenderMembershipEvent(
+        realm: Realm,
+        senderMembershipEventId: String
+): List<TimelineEventEntity> {
     return where(realm)
             .equalTo(TimelineEventEntityFields.SENDER_MEMBERSHIP_EVENT_ID, senderMembershipEventId)
             .findAll()
 }
 
-internal fun TimelineEventEntity.Companion.latestEvent(realm: Realm,
-                                                       roomId: String,
-                                                       includesSending: Boolean,
-                                                       filters: TimelineEventFilters = TimelineEventFilters()): TimelineEventEntity? {
+internal fun TimelineEventEntity.Companion.latestEvent(
+        realm: Realm,
+        roomId: String,
+        includesSending: Boolean,
+        filters: TimelineEventFilters = TimelineEventFilters()
+): TimelineEventEntity? {
     val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: return null
     val sendingTimelineEvents = roomEntity.sendingTimelineEvents.where().filterEvents(filters)
 
@@ -129,9 +139,11 @@ internal fun RealmList<TimelineEventEntity>.find(eventId: String): TimelineEvent
             .findFirst()
 }
 
-internal fun TimelineEventEntity.Companion.findAllInRoomWithSendStates(realm: Realm,
-                                                                       roomId: String,
-                                                                       sendStates: List<SendState>): RealmResults<TimelineEventEntity> {
+internal fun TimelineEventEntity.Companion.findAllInRoomWithSendStates(
+        realm: Realm,
+        roomId: String,
+        sendStates: List<SendState>
+): RealmResults<TimelineEventEntity> {
     return whereRoomId(realm, roomId)
             .filterSendStates(sendStates)
             .findAll()
@@ -145,8 +157,10 @@ internal fun RealmQuery<TimelineEventEntity>.filterSendStates(sendStates: List<S
 /**
  * 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> {
+internal fun TimelineEventEntity.Companion.findAllFrom(
+        realm: Realm,
+        senderIds: Collection<String>
+): RealmResults<TimelineEventEntity> {
     return where(realm)
             .`in`(TimelineEventEntityFields.ROOT.SENDER, senderIds.toTypedArray())
             .isNull(TimelineEventEntityFields.ROOT.STATE_KEY)
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 dbc6aac6b59a329f0685b36880d268217d5a178a..095916643cb8d5e7fc35e54a72d1e65cfa3af103 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
@@ -100,7 +100,9 @@ internal interface MatrixComponent {
 
     @Component.Factory
     interface Factory {
-        fun create(@BindsInstance context: Context,
-                   @BindsInstance matrixConfiguration: MatrixConfiguration): MatrixComponent
+        fun create(
+                @BindsInstance context: Context,
+                @BindsInstance matrixConfiguration: MatrixConfiguration
+        ): MatrixComponent
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt
index 0cbbe1210d288918441532e24e69eef13a448090..862cf463b2c2ce7e1316c4bda26dea59a09d9c97 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt
@@ -62,13 +62,15 @@ internal object NetworkModule {
     @Provides
     @JvmStatic
     @Unauthenticated
-    fun providesOkHttpClient(matrixConfiguration: MatrixConfiguration,
-                             stethoInterceptor: StethoInterceptor,
-                             timeoutInterceptor: TimeOutInterceptor,
-                             userAgentInterceptor: UserAgentInterceptor,
-                             httpLoggingInterceptor: HttpLoggingInterceptor,
-                             curlLoggingInterceptor: CurlLoggingInterceptor,
-                             apiInterceptor: ApiInterceptor): OkHttpClient {
+    fun providesOkHttpClient(
+            matrixConfiguration: MatrixConfiguration,
+            stethoInterceptor: StethoInterceptor,
+            timeoutInterceptor: TimeOutInterceptor,
+            userAgentInterceptor: UserAgentInterceptor,
+            httpLoggingInterceptor: HttpLoggingInterceptor,
+            curlLoggingInterceptor: CurlLoggingInterceptor,
+            apiInterceptor: ApiInterceptor
+    ): OkHttpClient {
         val spec = ConnectionSpec.Builder(matrixConfiguration.connectionSpec).build()
 
         return OkHttpClient.Builder()
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 c59936af94d314a31dd11708731c0ed2b4038132..ad28286a849a1f1769d4eca703980a76c3d3ac2f 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
@@ -59,8 +59,10 @@ internal class WorkManagerProvider @Inject constructor(
     /**
      * Create a PeriodicWorkRequestBuilder, with the Matrix SDK tag.
      */
-    inline fun <reified W : ListenableWorker> matrixPeriodicWorkRequestBuilder(repeatInterval: Long,
-                                                                               repeatIntervalTimeUnit: TimeUnit) =
+    inline fun <reified W : ListenableWorker> matrixPeriodicWorkRequestBuilder(
+            repeatInterval: Long,
+            repeatIntervalTimeUnit: TimeUnit
+    ) =
             PeriodicWorkRequestBuilder<W>(repeatInterval, repeatIntervalTimeUnit)
                     .addTag(tag)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/federation/FederationModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/federation/FederationModule.kt
index a4eef80c58eb0e63f9da9723c04c11b12514df90..bbb29b6255229d4ad529d4ffe75001643493d964 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/federation/FederationModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/federation/FederationModule.kt
@@ -34,9 +34,11 @@ internal abstract class FederationModule {
     companion object {
         @Provides
         @JvmStatic
-        fun providesFederationAPI(@Unauthenticated okHttpClient: Lazy<OkHttpClient>,
-                                  sessionParams: SessionParams,
-                                  retrofitFactory: RetrofitFactory): FederationAPI {
+        fun providesFederationAPI(
+                @Unauthenticated okHttpClient: Lazy<OkHttpClient>,
+                sessionParams: SessionParams,
+                retrofitFactory: RetrofitFactory
+        ): FederationAPI {
             return retrofitFactory.create(okHttpClient, sessionParams.homeServerUrlBase)
                     .create(FederationAPI::class.java)
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt
index 0a76fb2eef7172b0e1a83590ab876ab07d685f95..56d9cc21439ca6ab0081b53d02a1f2048f410f76 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt
@@ -132,7 +132,7 @@ internal class DefaultLegacySessionImporter @Inject constructor(
                                     bytes = it.bytes,
                                     hashType = when (it.type) {
                                         LegacyFingerprint.HashType.SHA1,
-                                        null                              -> Fingerprint.HashType.SHA1
+                                        null -> Fingerprint.HashType.SHA1
                                         LegacyFingerprint.HashType.SHA256 -> Fingerprint.HashType.SHA256
                                     }
                             )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/HomeServerConnectionConfig.java b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/HomeServerConnectionConfig.java
index a1b46f6c09450e7e9f5ec7e6eb981bc84ec01811..b2bb852cd1a842c8c84035a1c36066d45b7bbdbb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/HomeServerConnectionConfig.java
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/HomeServerConnectionConfig.java
@@ -612,7 +612,7 @@ public class HomeServerConnectionConfig {
          * - https://www.ssi.gouv.fr/uploads/2017/02/security-recommendations-for-tls_v1.1.pdf
          * - https://developer.android.com/reference/javax/net/ssl/SSLEngine
          *
-         * @param tlsLimitations          true to use Tls limitations
+         * @param tlsLimitations true to use Tls limitations
          * @param enableCompatibilityMode set to true for Android < 20
          * @return this builder
          */
@@ -649,7 +649,7 @@ public class HomeServerConnectionConfig {
 
         /**
          * @param proxyHostname Proxy Hostname
-         * @param proxyPort     Proxy Port
+         * @param proxyPort Proxy Port
          * @return this builder
          */
         public Builder withProxy(@Nullable String proxyHostname, int proxyPort) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkCallbackStrategy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkCallbackStrategy.kt
index 8e18d2d8508c8636b6e7a054432e97d1020a74e4..f75fb01746609097d9c4bb9a6136ae6a95a76282 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkCallbackStrategy.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkCallbackStrategy.kt
@@ -31,8 +31,10 @@ internal interface NetworkCallbackStrategy {
     fun unregister()
 }
 
-internal class FallbackNetworkCallbackStrategy @Inject constructor(private val context: Context,
-                                                                   private val networkInfoReceiver: NetworkInfoReceiver) : NetworkCallbackStrategy {
+internal class FallbackNetworkCallbackStrategy @Inject constructor(
+        private val context: Context,
+        private val networkInfoReceiver: NetworkInfoReceiver
+) : NetworkCallbackStrategy {
 
     @Suppress("DEPRECATION")
     val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
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 65bf3fcadf926303670501e01b92b54f07fef1e2..c54227a7866c43c3641ca61e1316b0d8a599dd59 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
@@ -41,9 +41,11 @@ internal interface NetworkConnectivityChecker {
 }
 
 @SessionScope
-internal class DefaultNetworkConnectivityChecker @Inject constructor(private val homeServerPinger: HomeServerPinger,
-                                                                     private val backgroundDetectionObserver: BackgroundDetectionObserver,
-                                                                     private val networkCallbackStrategy: NetworkCallbackStrategy) :
+internal class DefaultNetworkConnectivityChecker @Inject constructor(
+        private val homeServerPinger: HomeServerPinger,
+        private val backgroundDetectionObserver: BackgroundDetectionObserver,
+        private val networkCallbackStrategy: NetworkCallbackStrategy
+) :
         NetworkConnectivityChecker {
 
     private val hasInternetAccess = AtomicBoolean(true)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ProgressRequestBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ProgressRequestBody.kt
index 818d7d6af3a65ae88afb536ccf7f5df84568fb51..6e4d064a0f463a5bab76b2f448e37956bc4f141b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ProgressRequestBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ProgressRequestBody.kt
@@ -26,8 +26,10 @@ import okio.buffer
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import java.io.IOException
 
-internal class ProgressRequestBody(private val delegate: RequestBody,
-                                   private val listener: Listener) : RequestBody() {
+internal class ProgressRequestBody(
+        private val delegate: RequestBody,
+        private val listener: Listener
+) : RequestBody() {
 
     private lateinit var countingSink: CountingSink
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt
index 695e7525af09580b8db70c40d3552a38a55b0252..fefb7fb5e33676369e1895e4993649d6ab39d259 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt
@@ -32,6 +32,7 @@ import java.io.IOException
  * Execute a request from the requestBlock and handle some of the Exception it could generate
  * Ref: https://github.com/matrix-org/matrix-js-sdk/blob/develop/src/scheduler.js#L138-L175
  *
+ * @param DATA type of data return by the [requestBlock]
  * @param globalErrorReceiver will be use to notify error such as invalid token error. See [GlobalError]
  * @param canRetry if set to true, the request will be executed again in case of error, after a delay
  * @param maxDelayBeforeRetry the max delay to wait before a retry. Note that in the case of a 429, if the provided delay exceeds this value, the error will
@@ -39,11 +40,13 @@ import java.io.IOException
  * @param maxRetriesCount the max number of retries
  * @param requestBlock a suspend lambda to perform the network request
  */
-internal suspend inline fun <DATA> executeRequest(globalErrorReceiver: GlobalErrorReceiver?,
-                                                  canRetry: Boolean = false,
-                                                  maxDelayBeforeRetry: Long = 32_000L,
-                                                  maxRetriesCount: Int = 4,
-                                                  noinline requestBlock: suspend () -> DATA): DATA {
+internal suspend inline fun <DATA> executeRequest(
+        globalErrorReceiver: GlobalErrorReceiver?,
+        canRetry: Boolean = false,
+        maxDelayBeforeRetry: Long = 32_000L,
+        maxRetriesCount: Int = 4,
+        noinline requestBlock: suspend () -> DATA
+): DATA {
     var currentRetryCount = 0
     var currentDelay = 1_000L
 
@@ -53,8 +56,8 @@ internal suspend inline fun <DATA> executeRequest(globalErrorReceiver: GlobalErr
         } catch (throwable: Throwable) {
             val exception = when (throwable) {
                 is KotlinNullPointerException -> IllegalStateException("The request returned a null body")
-                is HttpException              -> throwable.toFailure(globalErrorReceiver)
-                else                          -> throwable
+                is HttpException -> throwable.toFailure(globalErrorReceiver)
+                else -> throwable
             }
 
             // Log some details about the request which has failed.
@@ -91,11 +94,11 @@ internal suspend inline fun <DATA> executeRequest(globalErrorReceiver: GlobalErr
                 // Try again (loop)
             } else {
                 throw when (exception) {
-                    is IOException           -> Failure.NetworkConnection(exception)
+                    is IOException -> Failure.NetworkConnection(exception)
                     is Failure.ServerError,
                     is Failure.OtherServerError,
                     is CancellationException -> exception
-                    else                     -> Failure.Unknown(exception)
+                    else -> Failure.Unknown(exception)
                 }
             }
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RequestExecutor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RequestExecutor.kt
index 71df7c08be9c63607e1d622619bbaf857f70410d..2e8b2bc7717e21944d37a9d16ce35cf065f9402a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RequestExecutor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RequestExecutor.kt
@@ -19,19 +19,23 @@ package org.matrix.android.sdk.internal.network
 import org.matrix.android.sdk.internal.network.executeRequest as internalExecuteRequest
 
 internal interface RequestExecutor {
-    suspend fun <DATA> executeRequest(globalErrorReceiver: GlobalErrorReceiver?,
-                                      canRetry: Boolean = false,
-                                      maxDelayBeforeRetry: Long = 32_000L,
-                                      maxRetriesCount: Int = 4,
-                                      requestBlock: suspend () -> DATA): DATA
+    suspend fun <DATA> executeRequest(
+            globalErrorReceiver: GlobalErrorReceiver?,
+            canRetry: Boolean = false,
+            maxDelayBeforeRetry: Long = 32_000L,
+            maxRetriesCount: Int = 4,
+            requestBlock: suspend () -> DATA
+    ): DATA
 }
 
 internal object DefaultRequestExecutor : RequestExecutor {
-    override suspend fun <DATA> executeRequest(globalErrorReceiver: GlobalErrorReceiver?,
-                                               canRetry: Boolean,
-                                               maxDelayBeforeRetry: Long,
-                                               maxRetriesCount: Int,
-                                               requestBlock: suspend () -> DATA): DATA {
+    override suspend fun <DATA> executeRequest(
+            globalErrorReceiver: GlobalErrorReceiver?,
+            canRetry: Boolean,
+            maxDelayBeforeRetry: Long,
+            maxRetriesCount: Int,
+            requestBlock: suspend () -> DATA
+    ): DATA {
         return internalExecuteRequest(globalErrorReceiver, canRetry, maxDelayBeforeRetry, maxRetriesCount, requestBlock)
     }
 }
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 5268ea851d5f54d6e67562b4fa52ae4ab5fb045e..30f7cdd65b718d7b61655102c2627b5153d41d4d 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
@@ -92,10 +92,10 @@ private fun toFailure(errorBody: ResponseBody?, httpCode: Int, globalErrorReceiv
                     globalErrorReceiver?.handleGlobalError(GlobalError.ConsentNotGivenError(matrixError.consentUri))
                 }
                 httpCode == HttpURLConnection.HTTP_UNAUTHORIZED && /* 401 */
-                        matrixError.code == MatrixError.M_UNKNOWN_TOKEN                                        -> {
+                        matrixError.code == MatrixError.M_UNKNOWN_TOKEN -> {
                     globalErrorReceiver?.handleGlobalError(GlobalError.InvalidToken(matrixError.isSoftLogout.orFalse()))
                 }
-                matrixError.code == MatrixError.ORG_MATRIX_EXPIRED_ACCOUNT                                     -> {
+                matrixError.code == MatrixError.ORG_MATRIX_EXPIRED_ACCOUNT -> {
                     globalErrorReceiver?.handleGlobalError(GlobalError.ExpiredAccount)
                 }
             }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UnitConverterFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UnitConverterFactory.kt
index f2571ab73fafaf60d9b5a96a0d92a2600b86b257..8dcff59cbab33c4d2788335f00d2f392c7e57fc2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UnitConverterFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UnitConverterFactory.kt
@@ -22,8 +22,10 @@ import retrofit2.Retrofit
 import java.lang.reflect.Type
 
 internal object UnitConverterFactory : Converter.Factory() {
-    override fun responseBodyConverter(type: Type, annotations: Array<out Annotation>,
-                                       retrofit: Retrofit): Converter<ResponseBody, *>? {
+    override fun responseBodyConverter(
+            type: Type, annotations: Array<out Annotation>,
+            retrofit: Retrofit
+    ): Converter<ResponseBody, *>? {
         return if (type == Unit::class.java) UnitConverter else null
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt
index 00e15c283e210169d952511780bbd2482cb4d0c4..28d96dfce7363f2ed58402109467c959557bf862 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt
@@ -24,8 +24,10 @@ import timber.log.Timber
 import javax.inject.Inject
 
 @MatrixScope
-internal class UserAgentHolder @Inject constructor(private val context: Context,
-                                                   matrixConfiguration: MatrixConfiguration) {
+internal class UserAgentHolder @Inject constructor(
+        private val context: Context,
+        matrixConfiguration: MatrixConfiguration
+) {
 
     var userAgent: String = ""
         private set
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/ForceToBoolean.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/ForceToBoolean.kt
index 628486bb5fab22258b77f105e042b0e4ada7a601..b4925429d01234d2389970eabf7cb78483de3192 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/ForceToBoolean.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/ForceToBoolean.kt
@@ -37,9 +37,9 @@ internal class ForceToBooleanJsonAdapter {
     @ForceToBoolean
     fun fromJson(reader: JsonReader): Boolean {
         return when (val token = reader.peek()) {
-            JsonReader.Token.NUMBER  -> reader.nextInt() != 0
+            JsonReader.Token.NUMBER -> reader.nextInt() != 0
             JsonReader.Token.BOOLEAN -> reader.nextBoolean()
-            else                     -> {
+            else -> {
                 Timber.e("Expecting a boolean or a int but get: $token")
                 reader.skipValue()
                 false
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 40d174ee2d5df87d09b22aa8bf6847467ed601f8..7cf3603cc57636da3032a977f497d4082e6eb522 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
@@ -70,11 +70,13 @@ internal class RuntimeJsonAdapterFactory<T>(
     }
 
     @Suppress("UNCHECKED_CAST")
-    internal class RuntimeJsonAdapter(val labelKey: String,
-                                      val labelToAdapter: Map<String, JsonAdapter<Any>>,
-                                      val typeToLabel: Map<Type, String>,
-                                      val objectJsonAdapter: JsonAdapter<Any>,
-                                      val fallbackAdapter: JsonAdapter<Any>) : JsonAdapter<Any?>() {
+    internal class RuntimeJsonAdapter(
+            val labelKey: String,
+            val labelToAdapter: Map<String, JsonAdapter<Any>>,
+            val typeToLabel: Map<Type, String>,
+            val objectJsonAdapter: JsonAdapter<Any>,
+            val fallbackAdapter: JsonAdapter<Any>
+    ) : JsonAdapter<Any?>() {
         @Throws(IOException::class)
         override fun fromJson(reader: JsonReader): Any? {
             val peekedToken = reader.peek()
@@ -119,9 +121,11 @@ internal class RuntimeJsonAdapterFactory<T>(
 
     companion object {
         /**
+         * @param T the generic type to pass to [RuntimeJsonAdapterFactory]
          * @param baseType The base type for which this factory will create adapters. Cannot be Object.
          * @param labelKey The key in the JSON object whose value determines the type to which to map the
          * JSON object.
+         * @param fallbackType alternative Type to try in case of the serialization fails
          */
         @CheckReturnValue
         fun <T> of(baseType: Class<T>, labelKey: String, fallbackType: Class<out T>): RuntimeJsonAdapterFactory<T> {
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 2ef40fe2a3fbb162b8ce3ef1800081cdffd18124..e5659fd76b317229e8579eafb18d2a12d4ce309f 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
@@ -94,6 +94,7 @@ internal object CertUtil {
      * Convert the fingerprint to an hexa string.
      *
      * @param fingerprint the fingerprint
+     * @param sep the separator character, default to space
      * @return the hexa string.
      */
     fun fingerprintToHexString(fingerprint: ByteArray, sep: Char = ' '): String {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManager.kt
index ccae5ad14f98c08c84c632f3fa56fbdf16b67d68..1b957c385539ea1ab6dd91074b39e0a9e7a7eaf4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManager.kt
@@ -24,15 +24,15 @@ import javax.net.ssl.X509TrustManager
 /**
  * Implements a TrustManager that checks Certificates against an explicit list of known
  * fingerprints.
- */
-
-/**
- * @param fingerprints        Not empty array of SHA256 cert fingerprints
- * @param defaultTrustManager Optional trust manager to fall back on if cert does not match
+ *
+ * @property fingerprints Not empty array of SHA256 cert fingerprints
+ * @property defaultTrustManager Optional trust manager to fall back on if cert does not match
  * any of the fingerprints. Can be null.
  */
-internal class PinnedTrustManager(private val fingerprints: List<Fingerprint>,
-                                  private val defaultTrustManager: X509TrustManager?) : X509TrustManager {
+internal class PinnedTrustManager(
+        private val fingerprints: List<Fingerprint>,
+        private val defaultTrustManager: X509TrustManager?
+) : X509TrustManager {
 
     @Throws(CertificateException::class)
     override fun checkClientTrusted(chain: Array<X509Certificate>, s: String) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerApi24.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerApi24.kt
index 574f1ef81db6fcfe8cfcc642bbea6ac1ef26d2e3..ef703f3b61ae2f4a5ae40b86f37d30630d0e0e74 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerApi24.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerApi24.kt
@@ -28,16 +28,16 @@ import javax.net.ssl.X509ExtendedTrustManager
 /**
  * Implements a TrustManager that checks Certificates against an explicit list of known
  * fingerprints.
- */
-
-/**
- * @param fingerprints        An array of SHA256 cert fingerprints
- * @param defaultTrustManager Optional trust manager to fall back on if cert does not match
+ *
+ * @property fingerprints An array of SHA256 cert fingerprints
+ * @property defaultTrustManager Optional trust manager to fall back on if cert does not match
  * any of the fingerprints. Can be null.
  */
 @RequiresApi(Build.VERSION_CODES.N)
-internal class PinnedTrustManagerApi24(private val fingerprints: List<Fingerprint>,
-                                       private val defaultTrustManager: X509ExtendedTrustManager?) : X509ExtendedTrustManager() {
+internal class PinnedTrustManagerApi24(
+        private val fingerprints: List<Fingerprint>,
+        private val defaultTrustManager: X509ExtendedTrustManager?
+) : X509ExtendedTrustManager() {
 
     @Throws(CertificateException::class)
     override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String, engine: SSLEngine?) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerProvider.kt
index f01ee7af24fa04ed6e993fac9a21ae4d0aaa436e..bfdc4e537ee21cd7917946f50a0d502fd3032be8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerProvider.kt
@@ -25,8 +25,10 @@ internal object PinnedTrustManagerProvider {
     // Set to false to perform some tests
     private const val USE_DEFAULT_TRUST_MANAGER = true
 
-    fun provide(fingerprints: List<Fingerprint>?,
-                defaultTrustManager: X509TrustManager?): X509TrustManager {
+    fun provide(
+            fingerprints: List<Fingerprint>?,
+            defaultTrustManager: X509TrustManager?
+    ): X509TrustManager {
         return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && defaultTrustManager is X509ExtendedTrustManager) {
             PinnedTrustManagerApi24(
                     fingerprints.orEmpty(),
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 c5ea2d48ad4e517cd8d75cacd2598b46140f6e80..8df048299394713c8bf18af54c24200bcfca5737 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
@@ -24,10 +24,10 @@ import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
 
 internal fun RealmQuery<RoomSummaryEntity>.process(sortOrder: RoomSortOrder): RealmQuery<RoomSummaryEntity> {
     when (sortOrder) {
-        RoomSortOrder.NAME                  -> {
+        RoomSortOrder.NAME -> {
             sort(RoomSummaryEntityFields.DISPLAY_NAME, Sort.ASCENDING)
         }
-        RoomSortOrder.ACTIVITY              -> {
+        RoomSortOrder.ACTIVITY -> {
             sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
         }
         RoomSortOrder.PRIORITY_AND_ACTIVITY -> {
@@ -40,7 +40,7 @@ internal fun RealmQuery<RoomSummaryEntity>.process(sortOrder: RoomSortOrder): Re
                     arrayOf(Sort.DESCENDING, Sort.ASCENDING, Sort.DESCENDING)
             )
         }
-        RoomSortOrder.NONE                  -> {
+        RoomSortOrder.NONE -> {
         }
     }
     return this
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt
index ba4d05e747a47b246a59ed54d067f04774cb7c7d..b2ab9879df934ed0047d684b9241d925d23a8331 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt
@@ -31,12 +31,12 @@ internal class QueryStringValueProcessor @Inject constructor(
     fun <T : RealmObject> RealmQuery<T>.process(field: String, queryStringValue: QueryStringValue): RealmQuery<T> {
         return when (queryStringValue) {
             is QueryStringValue.NoCondition -> this
-            is QueryStringValue.IsNotNull   -> isNotNull(field)
-            is QueryStringValue.IsNull      -> isNull(field)
-            is QueryStringValue.IsEmpty     -> isEmpty(field)
-            is QueryStringValue.IsNotEmpty  -> isNotEmpty(field)
-            is ContentQueryStringValue      -> when (queryStringValue) {
-                is QueryStringValue.Equals   -> equalTo(field, queryStringValue.toRealmValue(), queryStringValue.case.toRealmCase())
+            is QueryStringValue.IsNotNull -> isNotNull(field)
+            is QueryStringValue.IsNull -> isNull(field)
+            is QueryStringValue.IsEmpty -> isEmpty(field)
+            is QueryStringValue.IsNotEmpty -> isNotEmpty(field)
+            is ContentQueryStringValue -> when (queryStringValue) {
+                is QueryStringValue.Equals -> equalTo(field, queryStringValue.toRealmValue(), queryStringValue.case.toRealmCase())
                 is QueryStringValue.Contains -> contains(field, queryStringValue.toRealmValue(), queryStringValue.case.toRealmCase())
             }
         }
@@ -44,7 +44,7 @@ internal class QueryStringValueProcessor @Inject constructor(
 
     private fun ContentQueryStringValue.toRealmValue(): String {
         return when (case) {
-            QueryStringValue.Case.NORMALIZED  -> normalizer.normalize(string)
+            QueryStringValue.Case.NORMALIZED -> normalizer.normalize(string)
             QueryStringValue.Case.SENSITIVE,
             QueryStringValue.Case.INSENSITIVE -> string
         }
@@ -55,6 +55,6 @@ private fun QueryStringValue.Case.toRealmCase(): Case {
     return when (this) {
         QueryStringValue.Case.INSENSITIVE -> Case.INSENSITIVE
         QueryStringValue.Case.SENSITIVE,
-        QueryStringValue.Case.NORMALIZED  -> Case.SENSITIVE
+        QueryStringValue.Case.NORMALIZED -> Case.SENSITIVE
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GetUrlTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GetUrlTask.kt
index d0e2534e7a1bf4f4ea014c693f87c6b6cb95d0f0..87adad9063514b8f742fcce8019005642d42de71 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GetUrlTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GetUrlTask.kt
@@ -42,8 +42,8 @@ internal class DefaultGetUrlTask @Inject constructor(
 
     override suspend fun execute(params: GetUrlTask.Params): String {
         return when (params.cacheStrategy) {
-            CacheStrategy.NoCache       -> doRequest(params.url)
-            is CacheStrategy.TtlCache   -> doRequestWithCache(
+            CacheStrategy.NoCache -> doRequest(params.url)
+            is CacheStrategy.TtlCache -> doRequestWithCache(
                     params.url,
                     params.cacheStrategy.validityDurationInMillis,
                     params.cacheStrategy.strict
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt
index a8309766710007e1101b488f97be61035bcfce8c..4b643f1fef7ecd35dcbcc539a5a537c1b2b2257a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt
@@ -51,8 +51,10 @@ internal abstract class RawModule {
         @Provides
         @GlobalDatabase
         @MatrixScope
-        fun providesRealmConfiguration(realmKeysUtils: RealmKeysUtils,
-                                       globalRealmMigration: GlobalRealmMigration): RealmConfiguration {
+        fun providesRealmConfiguration(
+                realmKeysUtils: RealmKeysUtils,
+                globalRealmMigration: GlobalRealmMigration
+        ): RealmConfiguration {
             return RealmConfiguration.Builder()
                     .apply {
                         realmKeysUtils.configureEncryption(this, DB_ALIAS)
@@ -67,8 +69,10 @@ internal abstract class RawModule {
 
         @Provides
         @JvmStatic
-        fun providesRawAPI(@Unauthenticated okHttpClient: Lazy<OkHttpClient>,
-                           retrofitFactory: RetrofitFactory): RawAPI {
+        fun providesRawAPI(
+                @Unauthenticated okHttpClient: Lazy<OkHttpClient>,
+                retrofitFactory: RetrofitFactory
+        ): RawAPI {
             return retrofitFactory.create(okHttpClient, "https://example.org").create(RawAPI::class.java)
         }
     }
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 760aa410817389bce1a762c2917669ebbccc3026..bbf260a3f135c002f187bb73ea951a9df705fd96 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
@@ -80,10 +80,12 @@ internal class DefaultFileService @Inject constructor(
      * Download file in the cache folder, and eventually decrypt it.
      * TODO looks like files are copied 3 times
      */
-    override suspend fun downloadFile(fileName: String,
-                                      mimeType: String?,
-                                      url: String?,
-                                      elementToDecrypt: ElementToDecrypt?): File {
+    override suspend fun downloadFile(
+            fileName: String,
+            mimeType: String?,
+            url: String?,
+            elementToDecrypt: ElementToDecrypt?
+    ): File {
         url ?: throw IllegalArgumentException("url is null")
 
         Timber.v("## FileService downloadFile $url")
@@ -125,7 +127,7 @@ internal class DefaultFileService @Inject constructor(
                     val resolvedUrl = contentUrlResolver.resolveForDownload(url, elementToDecrypt) ?: throw IllegalArgumentException("url is null")
 
                     val request = when (resolvedUrl) {
-                        is ContentUrlResolver.ResolvedMethod.GET  -> {
+                        is ContentUrlResolver.ResolvedMethod.GET -> {
                             Request.Builder()
                                     .url(resolvedUrl.url)
                                     .header(DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER, url)
@@ -218,11 +220,13 @@ internal class DefaultFileService @Inject constructor(
         return result.getOrThrow()
     }
 
-    fun storeDataFor(mxcUrl: String,
-                     filename: String?,
-                     mimeType: String?,
-                     originalFile: File,
-                     encryptedFile: File?) {
+    fun storeDataFor(
+            mxcUrl: String,
+            filename: String?,
+            mimeType: String?,
+            originalFile: File,
+            encryptedFile: File?
+    ) {
         val files = getFiles(mxcUrl, filename, mimeType, encryptedFile != null)
         if (encryptedFile != null) {
             // We switch the two files here, original file it the decrypted file
@@ -256,10 +260,12 @@ internal class DefaultFileService @Inject constructor(
         }
     }
 
-    override fun isFileInCache(mxcUrl: String?,
-                               fileName: String,
-                               mimeType: String?,
-                               elementToDecrypt: ElementToDecrypt?): Boolean {
+    override fun isFileInCache(
+            mxcUrl: String?,
+            fileName: String,
+            mimeType: String?,
+            elementToDecrypt: ElementToDecrypt?
+    ): Boolean {
         return fileState(mxcUrl, fileName, mimeType, elementToDecrypt) is FileService.FileState.InCache
     }
 
@@ -272,10 +278,12 @@ internal class DefaultFileService @Inject constructor(
         fun getClearFile(): File = decryptedFile ?: file
     }
 
-    private fun getFiles(mxcUrl: String,
-                         fileName: String?,
-                         mimeType: String?,
-                         isEncrypted: Boolean): CachedFiles {
+    private fun getFiles(
+            mxcUrl: String,
+            fileName: String?,
+            mimeType: String?,
+            isEncrypted: Boolean
+    ): CachedFiles {
         val hashFolder = mxcUrl.md5()
         val safeFileName = safeFileName(fileName, mimeType)
         return if (isEncrypted) {
@@ -293,10 +301,12 @@ internal class DefaultFileService @Inject constructor(
         }
     }
 
-    override fun fileState(mxcUrl: String?,
-                           fileName: String,
-                           mimeType: String?,
-                           elementToDecrypt: ElementToDecrypt?): FileService.FileState {
+    override fun fileState(
+            mxcUrl: String?,
+            fileName: String,
+            mimeType: String?,
+            elementToDecrypt: ElementToDecrypt?
+    ): FileService.FileState {
         mxcUrl ?: return FileService.FileState.Unknown
         val files = getFiles(mxcUrl, fileName, mimeType, elementToDecrypt != null)
         if (files.file.exists()) {
@@ -314,10 +324,12 @@ internal class DefaultFileService @Inject constructor(
      * Use this URI and pass it to intent using flag Intent.FLAG_GRANT_READ_URI_PERMISSION
      * (if not other app won't be able to access it).
      */
-    override fun getTemporarySharableURI(mxcUrl: String?,
-                                         fileName: String,
-                                         mimeType: String?,
-                                         elementToDecrypt: ElementToDecrypt?): Uri? {
+    override fun getTemporarySharableURI(
+            mxcUrl: String?,
+            fileName: String,
+            mimeType: String?,
+            elementToDecrypt: ElementToDecrypt?
+    ): Uri? {
         mxcUrl ?: return null
         // this string could be extracted no?
         val authority = "${context.packageName}.mx-sdk.fileprovider"
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt
index 5f77cfb23a702ec54ab3cdb615897e5b899eb4fa..32269c9afddbdbe0bf751e38c1743b9b5da7eedf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt
@@ -44,7 +44,6 @@ import org.matrix.android.sdk.api.session.file.FileService
 import org.matrix.android.sdk.api.session.group.GroupService
 import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
 import org.matrix.android.sdk.api.session.identity.IdentityService
-import org.matrix.android.sdk.api.session.initsync.SyncStatusService
 import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
 import org.matrix.android.sdk.api.session.media.MediaService
 import org.matrix.android.sdk.api.session.openid.OpenIdService
@@ -61,6 +60,7 @@ import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageServi
 import org.matrix.android.sdk.api.session.signout.SignOutService
 import org.matrix.android.sdk.api.session.space.SpaceService
 import org.matrix.android.sdk.api.session.sync.FilterService
+import org.matrix.android.sdk.api.session.sync.SyncService
 import org.matrix.android.sdk.api.session.terms.TermsService
 import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
 import org.matrix.android.sdk.api.session.typing.TypingUsersTracker
@@ -76,13 +76,8 @@ import org.matrix.android.sdk.internal.di.SessionId
 import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
 import org.matrix.android.sdk.internal.di.WorkManagerProvider
 import org.matrix.android.sdk.internal.network.GlobalErrorHandler
-import org.matrix.android.sdk.internal.session.sync.SyncTokenStore
-import org.matrix.android.sdk.internal.session.sync.job.SyncThread
-import org.matrix.android.sdk.internal.session.sync.job.SyncWorker
 import org.matrix.android.sdk.internal.util.createUIHandler
-import timber.log.Timber
 import javax.inject.Inject
-import javax.inject.Provider
 
 @SessionScope
 internal class DefaultSession @Inject constructor(
@@ -112,16 +107,14 @@ internal class DefaultSession @Inject constructor(
         private val permalinkService: Lazy<PermalinkService>,
         private val secureStorageService: Lazy<SecureStorageService>,
         private val profileService: Lazy<ProfileService>,
+        private val syncService: Lazy<SyncService>,
         private val mediaService: Lazy<MediaService>,
         private val widgetService: Lazy<WidgetService>,
-        private val syncThreadProvider: Provider<SyncThread>,
         private val contentUrlResolver: ContentUrlResolver,
-        private val syncTokenStore: SyncTokenStore,
         private val sessionParamsStore: SessionParamsStore,
         private val contentUploadProgressTracker: ContentUploadStateTracker,
         private val typingUsersTracker: TypingUsersTracker,
         private val contentDownloadStateTracker: ContentDownloadStateTracker,
-        private val syncStatusService: Lazy<SyncStatusService>,
         private val homeServerCapabilitiesService: Lazy<HomeServerCapabilitiesService>,
         private val accountDataService: Lazy<SessionAccountDataService>,
         private val sharedSecretStorageService: Lazy<SharedSecretStorageService>,
@@ -138,14 +131,11 @@ internal class DefaultSession @Inject constructor(
         private val toDeviceService: Lazy<ToDeviceService>,
         private val eventStreamService: Lazy<EventStreamService>,
         @UnauthenticatedWithCertificate
-        private val unauthenticatedWithCertificateOkHttpClient: Lazy<OkHttpClient>
+        private val unauthenticatedWithCertificateOkHttpClient: Lazy<OkHttpClient>,
+        private val sessionState: SessionState,
 ) : Session,
         GlobalErrorHandler.Listener {
 
-    private var isOpen = false
-
-    private var syncThread: SyncThread? = null
-
     private val uiHandler = createUIHandler()
 
     override val isOpenable: Boolean
@@ -153,8 +143,7 @@ internal class DefaultSession @Inject constructor(
 
     @MainThread
     override fun open() {
-        assert(!isOpen)
-        isOpen = true
+        sessionState.setIsOpen(true)
         globalErrorHandler.listener = this
         cryptoService.get().ensureDevice()
         uiHandler.post {
@@ -167,40 +156,9 @@ internal class DefaultSession @Inject constructor(
         }
     }
 
-    override fun requireBackgroundSync() {
-        SyncWorker.requireBackgroundSync(workManagerProvider, sessionId)
-    }
-
-    override fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long) {
-        SyncWorker.automaticallyBackgroundSync(workManagerProvider, sessionId, timeOutInSeconds, repeatDelayInSeconds)
-    }
-
-    override fun stopAnyBackgroundSync() {
-        SyncWorker.stopAnyBackgroundSync(workManagerProvider)
-    }
-
-    override fun startSync(fromForeground: Boolean) {
-        Timber.i("Starting sync thread")
-        assert(isOpen)
-        val localSyncThread = getSyncThread()
-        localSyncThread.setInitialForeground(fromForeground)
-        if (!localSyncThread.isAlive) {
-            localSyncThread.start()
-        } else {
-            localSyncThread.restart()
-            Timber.w("Attempt to start an already started thread")
-        }
-    }
-
-    override fun stopSync() {
-        assert(isOpen)
-        syncThread?.kill()
-        syncThread = null
-    }
-
     override fun close() {
-        assert(isOpen)
-        stopSync()
+        assert(sessionState.isOpen)
+        syncService.get().stopSync()
         // timelineEventDecryptor.destroy()
         uiHandler.post {
             lifecycleObservers.forEach { it.onSessionStopped(this) }
@@ -210,28 +168,12 @@ internal class DefaultSession @Inject constructor(
         }
         cryptoService.get().close()
         globalErrorHandler.listener = null
-        isOpen = false
-    }
-
-    override fun getSyncStateLive() = getSyncThread().liveState()
-
-    override fun syncFlow() = getSyncThread().syncFlow()
-
-    override fun getSyncState() = getSyncThread().currentState()
-
-    override fun hasAlreadySynced(): Boolean {
-        return syncTokenStore.getLastToken() != null
-    }
-
-    private fun getSyncThread(): SyncThread {
-        return syncThread ?: syncThreadProvider.get().also {
-            syncThread = it
-        }
+        sessionState.setIsOpen(false)
     }
 
     override suspend fun clearCache() {
-        stopSync()
-        stopAnyBackgroundSync()
+        syncService.get().stopSync()
+        syncService.get().stopAnyBackgroundSync()
         uiHandler.post {
             lifecycleObservers.forEach {
                 it.onClearCache(this)
@@ -271,7 +213,7 @@ internal class DefaultSession @Inject constructor(
     override fun pushersService(): PushersService = pushersService.get()
     override fun eventService(): EventService = eventService.get()
     override fun termsService(): TermsService = termsService.get()
-    override fun syncStatusService(): SyncStatusService = syncStatusService.get()
+    override fun syncService(): SyncService = syncService.get()
     override fun secureStorageService(): SecureStorageService = secureStorageService.get()
     override fun profileService(): ProfileService = profileService.get()
     override fun presenceService(): PresenceService = presenceService.get()
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 050480e6c955d58a4d4e01ed749c82cd1ba30ed8..f01451b6887e4b1b5e85b14ed5be44ada7664676 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
@@ -46,6 +46,7 @@ import org.matrix.android.sdk.internal.session.profile.ProfileModule
 import org.matrix.android.sdk.internal.session.pushers.AddPusherWorker
 import org.matrix.android.sdk.internal.session.pushers.PushersModule
 import org.matrix.android.sdk.internal.session.room.RoomModule
+import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.DeactivateLiveLocationShareWorker
 import org.matrix.android.sdk.internal.session.room.send.MultipleEventSendingDispatcherWorker
 import org.matrix.android.sdk.internal.session.room.send.RedactEventWorker
 import org.matrix.android.sdk.internal.session.room.send.SendEventWorker
@@ -131,10 +132,13 @@ internal interface SessionComponent {
 
     fun inject(worker: UpdateTrustWorker)
 
+    fun inject(worker: DeactivateLiveLocationShareWorker)
+
     @Component.Factory
     interface Factory {
         fun create(
                 matrixComponent: MatrixComponent,
-                @BindsInstance sessionParams: SessionParams): SessionComponent
+                @BindsInstance sessionParams: SessionParams
+        ): SessionComponent
     }
 }
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 7ceb89e892c24c8a27649b9985746f59633c0fba..2c2317de0d0ed7a6bd06526c109e1a9626d216b4 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
@@ -39,7 +39,6 @@ import org.matrix.android.sdk.api.session.ToDeviceService
 import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
 import org.matrix.android.sdk.api.session.events.EventService
 import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
-import org.matrix.android.sdk.api.session.initsync.SyncStatusService
 import org.matrix.android.sdk.api.session.openid.OpenIdService
 import org.matrix.android.sdk.api.session.permalinks.PermalinkService
 import org.matrix.android.sdk.api.session.securestorage.SecureStorageService
@@ -82,13 +81,12 @@ import org.matrix.android.sdk.internal.session.download.DownloadProgressIntercep
 import org.matrix.android.sdk.internal.session.events.DefaultEventService
 import org.matrix.android.sdk.internal.session.homeserver.DefaultHomeServerCapabilitiesService
 import org.matrix.android.sdk.internal.session.identity.DefaultIdentityService
-import org.matrix.android.sdk.internal.session.initsync.DefaultSyncStatusService
 import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManager
 import org.matrix.android.sdk.internal.session.openid.DefaultOpenIdService
 import org.matrix.android.sdk.internal.session.permalinks.DefaultPermalinkService
 import org.matrix.android.sdk.internal.session.room.EventRelationsAggregationProcessor
-import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.DefaultLiveLocationAggregationProcessor
-import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.LiveLocationAggregationProcessor
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.DefaultPollAggregationProcessor
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollAggregationProcessor
 import org.matrix.android.sdk.internal.session.room.create.RoomCreateEventProcessor
 import org.matrix.android.sdk.internal.session.room.prune.RedactionEventProcessor
 import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
@@ -166,9 +164,11 @@ internal abstract class SessionModule {
         @Provides
         @SessionFilesDirectory
         @SessionScope
-        fun providesFilesDir(@UserMd5 userMd5: String,
-                             @SessionId sessionId: String,
-                             context: Context): File {
+        fun providesFilesDir(
+                @UserMd5 userMd5: String,
+                @SessionId sessionId: String,
+                context: Context
+        ): File {
             // Temporary code for migration
             val old = File(context.filesDir, userMd5)
             if (old.exists()) {
@@ -181,8 +181,10 @@ internal abstract class SessionModule {
         @JvmStatic
         @Provides
         @SessionDownloadsDirectory
-        fun providesDownloadsCacheDir(@SessionId sessionId: String,
-                                      @CacheDirectory cacheFile: File): File {
+        fun providesDownloadsCacheDir(
+                @SessionId sessionId: String,
+                @CacheDirectory cacheFile: File
+        ): File {
             return File(cacheFile, "downloads/$sessionId")
         }
 
@@ -208,8 +210,10 @@ internal abstract class SessionModule {
         @Provides
         @SessionScope
         @UnauthenticatedWithCertificate
-        fun providesOkHttpClientWithCertificate(@Unauthenticated okHttpClient: OkHttpClient,
-                                                homeServerConnectionConfig: HomeServerConnectionConfig): OkHttpClient {
+        fun providesOkHttpClientWithCertificate(
+                @Unauthenticated okHttpClient: OkHttpClient,
+                homeServerConnectionConfig: HomeServerConnectionConfig
+        ): OkHttpClient {
             return okHttpClient
                     .newBuilder()
                     .addSocketFactory(homeServerConnectionConfig)
@@ -220,10 +224,12 @@ internal abstract class SessionModule {
         @Provides
         @SessionScope
         @Authenticated
-        fun providesOkHttpClient(@UnauthenticatedWithCertificate okHttpClient: OkHttpClient,
-                                 @Authenticated accessTokenProvider: AccessTokenProvider,
-                                 @SessionId sessionId: String,
-                                 @MockHttpInterceptor testInterceptor: TestInterceptor?): OkHttpClient {
+        fun providesOkHttpClient(
+                @UnauthenticatedWithCertificate okHttpClient: OkHttpClient,
+                @Authenticated accessTokenProvider: AccessTokenProvider,
+                @SessionId sessionId: String,
+                @MockHttpInterceptor testInterceptor: TestInterceptor?
+        ): OkHttpClient {
             return okHttpClient
                     .newBuilder()
                     .addAccessTokenInterceptor(accessTokenProvider)
@@ -240,8 +246,10 @@ internal abstract class SessionModule {
         @Provides
         @SessionScope
         @UnauthenticatedWithCertificateWithProgress
-        fun providesProgressOkHttpClient(@UnauthenticatedWithCertificate okHttpClient: OkHttpClient,
-                                         downloadProgressInterceptor: DownloadProgressInterceptor): OkHttpClient {
+        fun providesProgressOkHttpClient(
+                @UnauthenticatedWithCertificate okHttpClient: OkHttpClient,
+                downloadProgressInterceptor: DownloadProgressInterceptor
+        ): OkHttpClient {
             return okHttpClient.newBuilder()
                     .apply {
                         // Remove the previous CurlLoggingInterceptor, to add it after the accessTokenInterceptor
@@ -260,9 +268,11 @@ internal abstract class SessionModule {
         @JvmStatic
         @Provides
         @SessionScope
-        fun providesRetrofit(@Authenticated okHttpClient: Lazy<OkHttpClient>,
-                             sessionParams: SessionParams,
-                             retrofitFactory: RetrofitFactory): Retrofit {
+        fun providesRetrofit(
+                @Authenticated okHttpClient: Lazy<OkHttpClient>,
+                sessionParams: SessionParams,
+                retrofitFactory: RetrofitFactory
+        ): Retrofit {
             return retrofitFactory
                     .create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUriBase.toString())
         }
@@ -270,8 +280,9 @@ internal abstract class SessionModule {
         @JvmStatic
         @Provides
         @SessionScope
-        fun providesNetworkCallbackStrategy(fallbackNetworkCallbackStrategy: Provider<FallbackNetworkCallbackStrategy>,
-                                            preferredNetworkCallbackStrategy: Provider<PreferredNetworkCallbackStrategy>
+        fun providesNetworkCallbackStrategy(
+                fallbackNetworkCallbackStrategy: Provider<FallbackNetworkCallbackStrategy>,
+                preferredNetworkCallbackStrategy: Provider<PreferredNetworkCallbackStrategy>
         ): NetworkCallbackStrategy {
             return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                 preferredNetworkCallbackStrategy.get()
@@ -349,9 +360,6 @@ internal abstract class SessionModule {
     @IntoSet
     abstract fun bindEventSenderProcessorAsSessionLifecycleObserver(processor: EventSenderProcessorCoroutine): SessionLifecycleObserver
 
-    @Binds
-    abstract fun bindSyncStatusService(service: DefaultSyncStatusService): SyncStatusService
-
     @Binds
     abstract fun bindSecureStorageService(service: DefaultSecureStorageService): SecureStorageService
 
@@ -389,5 +397,5 @@ internal abstract class SessionModule {
     abstract fun bindEventSenderProcessor(processor: EventSenderProcessorCoroutine): EventSenderProcessor
 
     @Binds
-    abstract fun bindLiveLocationAggregationProcessor(processor: DefaultLiveLocationAggregationProcessor): LiveLocationAggregationProcessor
+    abstract fun bindPollAggregationProcessor(processor: DefaultPollAggregationProcessor): PollAggregationProcessor
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionState.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b109a9aa60305e7b3bbcd30506af32c27f0eb662
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionState.kt
@@ -0,0 +1,33 @@
+/*
+ * 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
+
+import javax.inject.Inject
+
+@SessionScope
+internal class SessionState @Inject constructor() {
+    var isOpen = false
+        private set
+
+    /**
+     * Set the new state. Throw if already in the new state.
+     */
+    fun setIsOpen(newState: Boolean) {
+        assert(newState != isOpen)
+        isOpen = newState
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt
index 9f3f1f649eea158658c51d6fa3f2e74cb60a2553..5f4d3d5fbce45f82b6aad115b73b520951431267 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt
@@ -60,10 +60,10 @@ internal class DefaultDeactivateAccountTask @Inject constructor(
                         execute(params.copy(userAuthParam = authUpdate))
                     }
             )) {
-                UiaResult.SUCCESS   -> {
+                UiaResult.SUCCESS -> {
                     false
                 }
-                UiaResult.FAILURE   -> {
+                UiaResult.FAILURE -> {
                     Timber.d("## UIA: propagate failure")
                     throw throwable
                 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt
index dc77d7bffb07b5fcf85120e35e90df3613f4628d..bb830a5e419a1bc42e906c0b0bbd9c4442d481b0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt
@@ -20,8 +20,10 @@ import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
 import org.matrix.android.sdk.api.session.account.AccountService
 import javax.inject.Inject
 
-internal class DefaultAccountService @Inject constructor(private val changePasswordTask: ChangePasswordTask,
-                                                         private val deactivateAccountTask: DeactivateAccountTask) : AccountService {
+internal class DefaultAccountService @Inject constructor(
+        private val changePasswordTask: ChangePasswordTask,
+        private val deactivateAccountTask: DeactivateAccountTask
+) : AccountService {
 
     override suspend fun changePassword(password: String, newPassword: String) {
         changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword))
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt
index c4f711a9e6fb33966a55e93bfde2b4c59b4a80eb..48a9dfd3dafd6af055ba2fe5aab06535c485cfed 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt
@@ -63,25 +63,25 @@ internal class CallSignalingHandler @Inject constructor(
 
     fun onCallEvent(event: Event) {
         when (event.getClearType()) {
-            EventType.CALL_ANSWER                   -> {
+            EventType.CALL_ANSWER -> {
                 handleCallAnswerEvent(event)
             }
-            EventType.CALL_INVITE                   -> {
+            EventType.CALL_INVITE -> {
                 handleCallInviteEvent(event)
             }
-            EventType.CALL_HANGUP                   -> {
+            EventType.CALL_HANGUP -> {
                 handleCallHangupEvent(event)
             }
-            EventType.CALL_REJECT                   -> {
+            EventType.CALL_REJECT -> {
                 handleCallRejectEvent(event)
             }
-            EventType.CALL_CANDIDATES               -> {
+            EventType.CALL_CANDIDATES -> {
                 handleCallCandidatesEvent(event)
             }
-            EventType.CALL_SELECT_ANSWER            -> {
+            EventType.CALL_SELECT_ANSWER -> {
                 handleCallSelectAnswerEvent(event)
             }
-            EventType.CALL_NEGOTIATE                -> {
+            EventType.CALL_NEGOTIATE -> {
                 handleCallNegotiateEvent(event)
             }
             EventType.CALL_ASSERTED_IDENTITY,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/MxCallFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/MxCallFactory.kt
index 9ec892b65db549942596b9b0d6e3f5068d0609e4..5b4100f276aae6ad7068bb1b24000b6dcc03d5da 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/MxCallFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/MxCallFactory.kt
@@ -79,10 +79,12 @@ internal class MxCallFactory @Inject constructor(
         }
     }
 
-    fun updateOutgoingCallWithOpponentData(call: MxCall,
-                                           userId: String,
-                                           content: CallSignalingContent,
-                                           callCapabilities: CallCapabilities?) {
+    fun updateOutgoingCallWithOpponentData(
+            call: MxCall,
+            userId: String,
+            content: CallSignalingContent,
+            callCapabilities: CallCapabilities?
+    ) {
         (call as? MxCallImpl)?.updateOpponentData(userId, content, callCapabilities)
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt
index 796e83311f89bde906a7c58eea9ca0112f1445cd..13a77e55e18e3cd3519a0e2237bbd282be1dac1b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt
@@ -220,10 +220,12 @@ internal class MxCallImpl(
                 .also { eventSenderProcessor.postEvent(it) }
     }
 
-    override suspend fun transfer(targetUserId: String,
-                                  targetRoomId: String?,
-                                  createCallId: String?,
-                                  awaitCallId: String?) {
+    override suspend fun transfer(
+            targetUserId: String,
+            targetRoomId: String?,
+            createCallId: String?,
+            awaitCallId: String?
+    ) {
         val profileInfoParams = GetProfileInfoTask.Params(targetUserId)
         val profileInfo = try {
             getProfileInfoTask.execute(profileInfoParams)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt
index 5d7742448234d467904f33273489d5da515623e3..ad2b9d0905e9f8944466e5f3a01f873871be19a0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt
@@ -80,9 +80,11 @@ internal class DefaultContentUrlResolver @Inject constructor(
                 }
     }
 
-    private fun resolve(contentUrl: String,
-                        toThumbnail: Boolean,
-                        params: String = ""): String {
+    private fun resolve(
+            contentUrl: String,
+            toThumbnail: Boolean,
+            params: String = ""
+    ): String {
         var serverAndMediaId = contentUrl.removeMxcPrefix()
 
         val apiPath = if (scannerService.isScannerEnabled()) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt
index f96a019fe22aabfeaeae39b8b9401d44d46152e9..c023646c7fa6e57f0b0f11f97dddb6b4cc7f6af9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt
@@ -62,10 +62,12 @@ internal class FileUploader @Inject constructor(
     private val uploadUrl = contentUrlResolver.uploadUrl
     private val responseAdapter = moshi.adapter(ContentUploadResponse::class.java)
 
-    suspend fun uploadFile(file: File,
-                           filename: String?,
-                           mimeType: String?,
-                           progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse {
+    suspend fun uploadFile(
+            file: File,
+            filename: String?,
+            mimeType: String?,
+            progressListener: ProgressRequestBody.Listener? = null
+    ): ContentUploadResponse {
         // Check size limit
         val maxUploadFileSize = homeServerCapabilitiesService.getHomeServerCapabilities().maxUploadFileSize
 
@@ -99,18 +101,22 @@ internal class FileUploader @Inject constructor(
         return upload(uploadBody, filename, progressListener)
     }
 
-    suspend fun uploadByteArray(byteArray: ByteArray,
-                                filename: String?,
-                                mimeType: String?,
-                                progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse {
+    suspend fun uploadByteArray(
+            byteArray: ByteArray,
+            filename: String?,
+            mimeType: String?,
+            progressListener: ProgressRequestBody.Listener? = null
+    ): ContentUploadResponse {
         val uploadBody = byteArray.toRequestBody(mimeType?.toMediaTypeOrNull())
         return upload(uploadBody, filename, progressListener)
     }
 
-    suspend fun uploadFromUri(uri: Uri,
-                              filename: String?,
-                              mimeType: String?,
-                              progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse {
+    suspend fun uploadFromUri(
+            uri: Uri,
+            filename: String?,
+            mimeType: String?,
+            progressListener: ProgressRequestBody.Listener? = null
+    ): ContentUploadResponse {
         val workingFile = context.copyUriToTempFile(uri)
         return uploadFile(workingFile, filename, mimeType, progressListener).also {
             tryOrNull { workingFile.delete() }
@@ -128,9 +134,11 @@ internal class FileUploader @Inject constructor(
         }
     }
 
-    private suspend fun upload(uploadBody: RequestBody,
-                               filename: String?,
-                               progressListener: ProgressRequestBody.Listener?): ContentUploadResponse {
+    private suspend fun upload(
+            uploadBody: RequestBody,
+            filename: String?,
+            progressListener: ProgressRequestBody.Listener?
+    ): ContentUploadResponse {
         val urlBuilder = uploadUrl.toHttpUrlOrNull()?.newBuilder() ?: throw RuntimeException()
 
         val httpUrl = urlBuilder
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt
index c5aa6cd5e717bc1864d32cbaf1f463161ccb8545..bc04cac35ab5c4d7c809e6705d231eb7493a7ee5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt
@@ -35,7 +35,8 @@ internal class ImageCompressor @Inject constructor(
             imageFile: File,
             desiredWidth: Int,
             desiredHeight: Int,
-            desiredQuality: Int = 80): File {
+            desiredQuality: Int = 80
+    ): File {
         return withContext(coroutineDispatchers.io) {
             val compressedBitmap = BitmapFactory.Options().run {
                 inJustDecodeBounds = true
@@ -68,20 +69,20 @@ internal class ImageCompressor @Inject constructor(
                     val orientation = exifInfo.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
                     val matrix = Matrix()
                     when (orientation) {
-                        ExifInterface.ORIENTATION_ROTATE_270      -> matrix.postRotate(270f)
-                        ExifInterface.ORIENTATION_ROTATE_180      -> matrix.postRotate(180f)
-                        ExifInterface.ORIENTATION_ROTATE_90       -> matrix.postRotate(90f)
+                        ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270f)
+                        ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180f)
+                        ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90f)
                         ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> matrix.preScale(-1f, 1f)
-                        ExifInterface.ORIENTATION_FLIP_VERTICAL   -> matrix.preScale(1f, -1f)
-                        ExifInterface.ORIENTATION_TRANSPOSE       -> {
+                        ExifInterface.ORIENTATION_FLIP_VERTICAL -> matrix.preScale(1f, -1f)
+                        ExifInterface.ORIENTATION_TRANSPOSE -> {
                             matrix.preRotate(-90f)
                             matrix.preScale(-1f, 1f)
                         }
-                        ExifInterface.ORIENTATION_TRANSVERSE      -> {
+                        ExifInterface.ORIENTATION_TRANSVERSE -> {
                             matrix.preRotate(90f)
                             matrix.preScale(-1f, 1f)
                         }
-                        else                                      -> return bitmap
+                        else -> return bitmap
                     }
                     return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
                 }
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 5a00c4b5b477f53bbeffef003063145bc8ca455b..1e62b5d7f5b2e63622b4c4aa437cd02617326140 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
@@ -192,7 +192,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
                     })
                             .let { videoCompressionResult ->
                                 when (videoCompressionResult) {
-                                    is VideoCompressionResult.Success           -> {
+                                    is VideoCompressionResult.Success -> {
                                         val compressedFile = videoCompressionResult.compressedFile
                                         var compressedWidth: Int? = null
                                         var compressedHeight: Int? = null
@@ -375,12 +375,14 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
         )
     }
 
-    private suspend fun handleSuccess(params: Params,
-                                      attachmentUrl: String,
-                                      encryptedFileInfo: EncryptedFileInfo?,
-                                      thumbnailUrl: String?,
-                                      thumbnailEncryptedFileInfo: EncryptedFileInfo?,
-                                      newAttachmentAttributes: NewAttachmentAttributes): Result {
+    private suspend fun handleSuccess(
+            params: Params,
+            attachmentUrl: String,
+            encryptedFileInfo: EncryptedFileInfo?,
+            thumbnailUrl: String?,
+            thumbnailEncryptedFileInfo: EncryptedFileInfo?,
+            newAttachmentAttributes: NewAttachmentAttributes
+    ): Result {
         notifyTracker(params) { contentUploadStateTracker.setSuccess(it) }
         params.localEchoIds.forEach {
             updateEvent(it.eventId, attachmentUrl, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo, newAttachmentAttributes)
@@ -396,20 +398,22 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
         }
     }
 
-    private suspend fun updateEvent(eventId: String,
-                                    url: String,
-                                    encryptedFileInfo: EncryptedFileInfo?,
-                                    thumbnailUrl: String? = null,
-                                    thumbnailEncryptedFileInfo: EncryptedFileInfo?,
-                                    newAttachmentAttributes: NewAttachmentAttributes) {
+    private suspend fun updateEvent(
+            eventId: String,
+            url: String,
+            encryptedFileInfo: EncryptedFileInfo?,
+            thumbnailUrl: String? = null,
+            thumbnailEncryptedFileInfo: EncryptedFileInfo?,
+            newAttachmentAttributes: NewAttachmentAttributes
+    ) {
         localEchoRepository.updateEcho(eventId) { _, event ->
             val messageContent: MessageContent? = event.asDomain().content.toModel()
             val updatedContent = when (messageContent) {
                 is MessageImageContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes)
                 is MessageVideoContent -> messageContent.update(url, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo, newAttachmentAttributes)
-                is MessageFileContent  -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes.newFileSize)
+                is MessageFileContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes.newFileSize)
                 is MessageAudioContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes.newFileSize)
-                else                   -> messageContent
+                else -> messageContent
             }
             event.content = ContentMapper.map(updatedContent.toContent())
         }
@@ -419,9 +423,11 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
         params.localEchoIds.forEach { function.invoke(it.eventId) }
     }
 
-    private fun MessageImageContent.update(url: String,
-                                           encryptedFileInfo: EncryptedFileInfo?,
-                                           newAttachmentAttributes: NewAttachmentAttributes?): MessageImageContent {
+    private fun MessageImageContent.update(
+            url: String,
+            encryptedFileInfo: EncryptedFileInfo?,
+            newAttachmentAttributes: NewAttachmentAttributes?
+    ): MessageImageContent {
         return copy(
                 url = if (encryptedFileInfo == null) url else null,
                 encryptedFileInfo = encryptedFileInfo?.copy(url = url),
@@ -433,11 +439,13 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
         )
     }
 
-    private fun MessageVideoContent.update(url: String,
-                                           encryptedFileInfo: EncryptedFileInfo?,
-                                           thumbnailUrl: String?,
-                                           thumbnailEncryptedFileInfo: EncryptedFileInfo?,
-                                           newAttachmentAttributes: NewAttachmentAttributes?): MessageVideoContent {
+    private fun MessageVideoContent.update(
+            url: String,
+            encryptedFileInfo: EncryptedFileInfo?,
+            thumbnailUrl: String?,
+            thumbnailEncryptedFileInfo: EncryptedFileInfo?,
+            newAttachmentAttributes: NewAttachmentAttributes?
+    ): MessageVideoContent {
         return copy(
                 url = if (encryptedFileInfo == null) url else null,
                 encryptedFileInfo = encryptedFileInfo?.copy(url = url),
@@ -451,9 +459,11 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
         )
     }
 
-    private fun MessageFileContent.update(url: String,
-                                          encryptedFileInfo: EncryptedFileInfo?,
-                                          size: Long): MessageFileContent {
+    private fun MessageFileContent.update(
+            url: String,
+            encryptedFileInfo: EncryptedFileInfo?,
+            size: Long
+    ): MessageFileContent {
         return copy(
                 url = if (encryptedFileInfo == null) url else null,
                 encryptedFileInfo = encryptedFileInfo?.copy(url = url),
@@ -461,9 +471,11 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
         )
     }
 
-    private fun MessageAudioContent.update(url: String,
-                                           encryptedFileInfo: EncryptedFileInfo?,
-                                           size: Long): MessageAudioContent {
+    private fun MessageAudioContent.update(
+            url: String,
+            encryptedFileInfo: EncryptedFileInfo?,
+            size: Long
+    ): MessageAudioContent {
         return copy(
                 url = if (encryptedFileInfo == null) url else null,
                 encryptedFileInfo = encryptedFileInfo?.copy(url = url),
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt
index a43f8abf3347b7b5286945b7057632e0ee96c0ec..5c00927e2356f8c112bc88219a9609ae98d6d09f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt
@@ -32,8 +32,10 @@ internal class VideoCompressor @Inject constructor(
         private val temporaryFileCreator: TemporaryFileCreator
 ) {
 
-    suspend fun compress(videoFile: File,
-                         progressListener: ProgressListener?): VideoCompressionResult {
+    suspend fun compress(
+            videoFile: File,
+            progressListener: ProgressListener?
+    ): VideoCompressionResult {
         val destinationFile = temporaryFileCreator.create()
 
         val job = Job()
@@ -111,7 +113,7 @@ internal class VideoCompressor @Inject constructor(
                 deleteFile(destinationFile)
                 VideoCompressionResult.CompressionNotNeeded
             }
-            else                          -> {
+            else -> {
                 // Should not happen...
                 // Delete now the temporary file
                 deleteFile(destinationFile)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerModule.kt
index 7ea74225cdac822c43b0acd2ae7e42ea3998bbd9..89b5c44ef0b97e198b214b0b29f770da8cc57adf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerModule.kt
@@ -49,9 +49,11 @@ internal abstract class ContentScannerModule {
         @Provides
         @ContentScannerDatabase
         @SessionScope
-        fun providesContentScannerRealmConfiguration(realmKeysUtils: RealmKeysUtils,
-                                                     @SessionFilesDirectory directory: File,
-                                                     @UserMd5 userMd5: String): RealmConfiguration {
+        fun providesContentScannerRealmConfiguration(
+                realmKeysUtils: RealmKeysUtils,
+                @SessionFilesDirectory directory: File,
+                @UserMd5 userMd5: String
+        ): RealmConfiguration {
             return RealmConfiguration.Builder()
                     .directory(directory)
                     .name("matrix-sdk-content-scanning.realm")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerEntityQueries.kt
index e4b64a1a0e5442183d9183c7cb7cf74af40c4629..bb3051bc965167a51280f3bd683e713b07330f05 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerEntityQueries.kt
@@ -31,10 +31,12 @@ internal fun ContentScanResultEntity.Companion.get(realm: Realm, attachmentUrl:
             .findFirst()
 }
 
-internal fun ContentScanResultEntity.Companion.getOrCreate(realm: Realm,
-                                                           attachmentUrl: String,
-                                                           contentScannerUrl: String?,
-                                                           currentTimeMillis: Long): ContentScanResultEntity {
+internal fun ContentScanResultEntity.Companion.getOrCreate(
+        realm: Realm,
+        attachmentUrl: String,
+        contentScannerUrl: String?,
+        currentTimeMillis: Long
+): ContentScanResultEntity {
     return ContentScanResultEntity.get(realm, attachmentUrl, contentScannerUrl)
             ?: realm.createObject<ContentScanResultEntity>().also {
                 it.mediaUrl = attachmentUrl
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/RealmContentScannerStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/RealmContentScannerStore.kt
index 27729d38c78679eeba49c8ea3ae9389fed8377a9..72dc15c1bdf2f67ec15200877997af380e558a1b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/RealmContentScannerStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/RealmContentScannerStore.kt
@@ -106,7 +106,7 @@ internal class RealmContentScannerStore @Inject constructor(
                 ScanState.IN_PROGRESS,
                 ScanState.TRUSTED,
                 ScanState.INFECTED -> true
-                else               -> false
+                else -> false
             }
         }
         return isKnown
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 19b9130fc4b6e7f63954c518fcb8d81a3f61d74f..488c61206b24afd25cf1439aea7faf4a21b6f2a6 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
@@ -49,16 +49,21 @@ internal interface DirectoryAPI {
      * @param body the body containing the new directory visibility
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "directory/list/room/{roomId}")
-    suspend fun setRoomDirectoryVisibility(@Path("roomId") roomId: String,
-                                           @Body body: RoomDirectoryVisibilityJson)
+    suspend fun setRoomDirectoryVisibility(
+            @Path("roomId") roomId: String,
+            @Body body: RoomDirectoryVisibilityJson
+    )
 
     /**
      * Add alias to the room.
      * @param roomAlias the room alias.
+     * @param body the Json body
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "directory/room/{roomAlias}")
-    suspend fun addRoomAlias(@Path("roomAlias") roomAlias: String,
-                             @Body body: AddRoomAliasBody)
+    suspend fun addRoomAlias(
+            @Path("roomAlias") roomAlias: String,
+            @Body body: AddRoomAliasBody
+    )
 
     /**
      * Delete a room alias.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/download/ProgressResponseBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/download/ProgressResponseBody.kt
index 4fd4fda7d1a9ea90c9c9ff357a0bb638cddc4aa9..4e0096b7dd6c40308d1b780b517d44c3f006bfde 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/download/ProgressResponseBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/download/ProgressResponseBody.kt
@@ -27,7 +27,8 @@ import okio.buffer
 internal class ProgressResponseBody(
         private val responseBody: ResponseBody,
         private val chainUrl: String,
-        private val progressListener: ProgressListener) : ResponseBody() {
+        private val progressListener: ProgressListener
+) : ResponseBody() {
 
     private var bufferedSource: BufferedSource? = null
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/DefaultFilterService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/DefaultFilterService.kt
index 9a16b8fd4a1ccac85dfb47c9a127aaf7c22a974e..2e68d02d8ce6b6427e6c23bff27b209ea0f219ba 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/DefaultFilterService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/DefaultFilterService.kt
@@ -21,8 +21,10 @@ import org.matrix.android.sdk.internal.task.TaskExecutor
 import org.matrix.android.sdk.internal.task.configureWith
 import javax.inject.Inject
 
-internal class DefaultFilterService @Inject constructor(private val saveFilterTask: SaveFilterTask,
-                                                        private val taskExecutor: TaskExecutor) : FilterService {
+internal class DefaultFilterService @Inject constructor(
+        private val saveFilterTask: SaveFilterTask,
+        private val taskExecutor: TaskExecutor
+) : FilterService {
 
     // TODO Pass a list of support events instead
     override fun setFilter(filterPreset: FilterService.FilterPreset) {
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 dab801360fd99e98aec6095020c76ba6b7437e6f..ac1e9a654ca8c6febcca0a0e5a8615ca6b990814 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
@@ -28,20 +28,24 @@ internal interface FilterApi {
      * 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
+     * @param body the Json representation of a FilterBody object
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/filter")
-    suspend fun uploadFilter(@Path("userId") userId: String,
-                             @Body body: Filter): FilterResponse
+    suspend fun uploadFilter(
+            @Path("userId") userId: String,
+            @Body body: Filter
+    ): FilterResponse
 
     /**
      * Gets a filter with a given filterId from the homeserver.
      *
-     * @param userId   the user id
+     * @param userId the user id
      * @param filterId the filterID
      * @return Filter
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/filter/{filterId}")
-    suspend fun getFilterById(@Path("userId") userId: String,
-                              @Path("filterId") filterId: String): Filter
+    suspend fun getFilterById(
+            @Path("userId") userId: String,
+            @Path("filterId") filterId: String
+    ): Filter
 }
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 562fea88b66c0b7fc015f98f2fe75b26618900b6..2017a86c39d100879746aaab4e42fda7459a390a 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
@@ -25,7 +25,7 @@ internal object FilterUtil {
      * FIXME New expected filter:
      * "{\"room\": {\"ephemeral\": {\"notTypes\": [\"m.typing\"]}}, \"presence\":{\"notTypes\": [\"*\"]}}"
      *
-     * @param filterBody      filterBody to patch
+     * @param filterBody filterBody to patch
      * @param useDataSaveMode true to enable data save mode
      */
     /*
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 e9d5b876a8d14512ec122aa72bdc9ab65589aea9..63afa1bbbc4a1bdf1c0dba08e1121caab3b44de8 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
@@ -45,7 +45,7 @@ internal class DefaultSaveFilterTask @Inject constructor(
             FilterService.FilterPreset.ElementFilter -> {
                 FilterFactory.createElementFilter()
             }
-            FilterService.FilterPreset.NoFilter      -> {
+            FilterService.FilterPreset.NoFilter -> {
                 FilterFactory.createDefaultFilter()
             }
         }
@@ -53,7 +53,7 @@ internal class DefaultSaveFilterTask @Inject constructor(
             FilterService.FilterPreset.ElementFilter -> {
                 FilterFactory.createElementRoomFilter()
             }
-            FilterService.FilterPreset.NoFilter      -> {
+            FilterService.FilterPreset.NoFilter -> {
                 FilterFactory.createDefaultRoomFilter()
             }
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/DefaultGroup.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/DefaultGroup.kt
index 4f610fd81bfe4176c6febcd8a89bfb80cc499e41..9c37d4db6c9ff2fafbc13159f7eef14d944dd083 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/DefaultGroup.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/DefaultGroup.kt
@@ -18,8 +18,10 @@ package org.matrix.android.sdk.internal.session.group
 
 import org.matrix.android.sdk.api.session.group.Group
 
-internal class DefaultGroup(override val groupId: String,
-                            private val getGroupDataTask: GetGroupDataTask) : Group {
+internal class DefaultGroup(
+        override val groupId: String,
+        private val getGroupDataTask: GetGroupDataTask
+) : Group {
 
     override suspend fun fetchGroupData() {
         val params = GetGroupDataTask.Params.FetchWithIds(listOf(groupId))
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataTask.kt
index 4e0ee3422b5e44721de045f68b62fad69c8f5266..235291d0617251bc28925e872fc7e555f9c09e1e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataTask.kt
@@ -58,7 +58,7 @@ internal class DefaultGetGroupDataTask @Inject constructor(
             is GetGroupDataTask.Params.FetchAllActive -> {
                 getActiveGroupIds()
             }
-            is GetGroupDataTask.Params.FetchWithIds   -> {
+            is GetGroupDataTask.Params.FetchWithIds -> {
                 params.groupIds
             }
         }
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 e9097e4d033f0721bc0f49d967413e7838be0f7f..d22da8f6f2102a4f6ce0cae9f318f06cbc5f117c 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
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.internal.session.homeserver
 
 import com.zhuinden.monarchy.Monarchy
-import org.matrix.android.sdk.api.MatrixPatterns.getDomain
+import org.matrix.android.sdk.api.MatrixPatterns.getServerName
 import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
 import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
 import org.matrix.android.sdk.api.extensions.orFalse
@@ -93,10 +93,14 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
             }
         }.getOrNull()
 
+        // Domain may include a port (eg, matrix.org:8080)
+        // Per https://spec.matrix.org/latest/client-server-api/#well-known-uri we should extract the hostname from the server name
+        // So we take everything before the last : as the domain for the well-known task.
+        // NB: This is not always the same endpoint as capabilities / mediaConfig uses.
         val wellknownResult = runCatching {
             getWellknownTask.execute(
                     GetWellknownTask.Params(
-                            domain = userId.getDomain(),
+                            domain = userId.getServerName().substringBeforeLast(":"),
                             homeServerConnectionConfig = homeServerConnectionConfig
                     )
             )
@@ -105,10 +109,12 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
         insertInDb(capabilities, mediaConfig, versions, wellknownResult)
     }
 
-    private suspend fun insertInDb(getCapabilitiesResult: GetCapabilitiesResult?,
-                                   getMediaConfigResult: GetMediaConfigResult?,
-                                   getVersionResult: Versions?,
-                                   getWellknownResult: WellknownResult?) {
+    private suspend fun insertInDb(
+            getCapabilitiesResult: GetCapabilitiesResult?,
+            getMediaConfigResult: GetMediaConfigResult?,
+            getVersionResult: Versions?,
+            getWellknownResult: WellknownResult?
+    ) {
         monarchy.awaitTransaction { realm ->
             val homeServerCapabilitiesEntity = HomeServerCapabilitiesEntity.getOrCreate(realm)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerPinger.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerPinger.kt
index 70e1e551aa0e0384edcf637b351311341d7dbfc7..a3d6b7fa4988f7937dd5110859215478adf3f26e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerPinger.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerPinger.kt
@@ -22,8 +22,10 @@ import org.matrix.android.sdk.internal.network.executeRequest
 import org.matrix.android.sdk.internal.task.TaskExecutor
 import javax.inject.Inject
 
-internal class HomeServerPinger @Inject constructor(private val taskExecutor: TaskExecutor,
-                                                    private val capabilitiesAPI: CapabilitiesAPI) {
+internal class HomeServerPinger @Inject constructor(
+        private val taskExecutor: TaskExecutor,
+        private val capabilitiesAPI: CapabilitiesAPI
+) {
 
     fun canReachHomeServer(callback: (Boolean) -> Unit) {
         taskExecutor.executorScope.launch {
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 74838afc6587b6eacfd4b58a2550f3c0a9db8dcf..30c7773a8e794dd01fdecfb6b9429c10d404dec2 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
@@ -283,8 +283,8 @@ internal class DefaultIdentityService @Inject constructor(
                     identityStore.setToken(null)
                     lookUpInternal(false, threePids)
                 }
-                throwable.isTermsNotSigned()           -> throw IdentityServiceError.TermsNotSignedException
-                else                                   -> throw throwable
+                throwable.isTermsNotSigned() -> throw IdentityServiceError.TermsNotSignedException
+                else -> throw throwable
             }
         }
     }
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 aef86ed08efaed4a3fe1feee081a4c304ff2e056..7b04bc52b03fc2c13ef17c09e824d86d9a3cdca2 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
@@ -95,8 +95,10 @@ internal interface IdentityAPI {
      * - https://matrix.org/docs/spec/identity_service/latest#post-matrix-identity-v2-validate-email-submittoken
      */
     @POST(NetworkConstants.URI_IDENTITY_PATH_V2 + "validate/{medium}/submitToken")
-    suspend fun submitToken(@Path("medium") medium: String,
-                            @Body body: IdentityRequestOwnershipParams): SuccessResult
+    suspend fun submitToken(
+            @Path("medium") medium: String,
+            @Body body: IdentityRequestOwnershipParams
+    ): SuccessResult
 
     /**
      * https://matrix.org/docs/spec/identity_service/r0.3.0#post-matrix-identity-v2-sign-ed25519.
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 f642ed4cf2f936574cf2de6366eac908f2b20396..21b59cca9dea70d4dc49c0913f08e05f19ed2bfd 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
@@ -75,10 +75,12 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor(
             val identityLookUpResponse: IdentityLookUpResponse
     )
 
-    private suspend fun lookUpInternal(identityAPI: IdentityAPI,
-                                       threePids: List<ThreePid>,
-                                       hashDetailResponse: IdentityHashDetailResponse,
-                                       canRetry: Boolean): LookUpData {
+    private suspend fun lookUpInternal(
+            identityAPI: IdentityAPI,
+            threePids: List<ThreePid>,
+            hashDetailResponse: IdentityHashDetailResponse,
+            canRetry: Boolean
+    ): LookUpData {
         val hashedAddresses = getHashedAddresses(threePids, hashDetailResponse.pepper)
         return try {
             LookUpData(hashedAddresses,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt
index 4e9d7dc7f764cad6d5cd0cee2265c6e3663d14e8..464ae96e3a4eda60f5fd7125767d257117e7bbe0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt
@@ -47,8 +47,10 @@ internal abstract class IdentityModule {
         @Provides
         @SessionScope
         @AuthenticatedIdentity
-        fun providesOkHttpClient(@UnauthenticatedWithCertificate okHttpClient: OkHttpClient,
-                                 @AuthenticatedIdentity accessTokenProvider: AccessTokenProvider): OkHttpClient {
+        fun providesOkHttpClient(
+                @UnauthenticatedWithCertificate okHttpClient: OkHttpClient,
+                @AuthenticatedIdentity accessTokenProvider: AccessTokenProvider
+        ): OkHttpClient {
             return okHttpClient
                     .newBuilder()
                     .addAccessTokenInterceptor(accessTokenProvider)
@@ -59,10 +61,12 @@ internal abstract class IdentityModule {
         @Provides
         @IdentityDatabase
         @SessionScope
-        fun providesIdentityRealmConfiguration(realmKeysUtils: RealmKeysUtils,
-                                               realmIdentityStoreMigration: RealmIdentityStoreMigration,
-                                               @SessionFilesDirectory directory: File,
-                                               @UserMd5 userMd5: String): RealmConfiguration {
+        fun providesIdentityRealmConfiguration(
+                realmKeysUtils: RealmKeysUtils,
+                realmIdentityStoreMigration: RealmIdentityStoreMigration,
+                @SessionFilesDirectory directory: File,
+                @UserMd5 userMd5: String
+        ): RealmConfiguration {
             return RealmConfiguration.Builder()
                     .directory(directory)
                     .name("matrix-sdk-identity.realm")
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 fe123096509fc4246693ec91a5cc3006ac0acbee..02462387fa1124f8a950db6116cb73259078870a 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,7 +57,7 @@ internal class DefaultIdentityRequestTokenForBindingTask @Inject constructor(
 
         val tokenResponse = executeRequest(null) {
             when (params.threePid) {
-                is ThreePid.Email  -> identityAPI.requestTokenToBindEmail(
+                is ThreePid.Email -> identityAPI.requestTokenToBindEmail(
                         IdentityRequestTokenForEmailBody(
                                 clientSecret = clientSecret,
                                 sendAttempt = sendAttempt,
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 aecf21678c12576fff363146adc0bb39beb7818a..08e5b4397723198646578f39d6e23271b42d1aeb 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
@@ -32,8 +32,10 @@ private fun IdentityDataEntity.Companion.getOrCreate(realm: Realm): IdentityData
     return get(realm) ?: realm.createObject()
 }
 
-internal fun IdentityDataEntity.Companion.setUrl(realm: Realm,
-                                                 url: String?) {
+internal fun IdentityDataEntity.Companion.setUrl(
+        realm: Realm,
+        url: String?
+) {
     realm.where<IdentityDataEntity>().findAll().deleteAllFromRealm()
     // Delete all pending binding if any
     IdentityPendingBindingEntity.deleteAll(realm)
@@ -45,23 +47,29 @@ internal fun IdentityDataEntity.Companion.setUrl(realm: Realm,
     }
 }
 
-internal fun IdentityDataEntity.Companion.setToken(realm: Realm,
-                                                   newToken: String?) {
+internal fun IdentityDataEntity.Companion.setToken(
+        realm: Realm,
+        newToken: String?
+) {
     get(realm)?.apply {
         token = newToken
     }
 }
 
-internal fun IdentityDataEntity.Companion.setUserConsent(realm: Realm,
-                                                         newConsent: Boolean) {
+internal fun IdentityDataEntity.Companion.setUserConsent(
+        realm: Realm,
+        newConsent: Boolean
+) {
     get(realm)?.apply {
         userConsent = newConsent
     }
 }
 
-internal fun IdentityDataEntity.Companion.setHashDetails(realm: Realm,
-                                                         pepper: String,
-                                                         algorithms: List<String>) {
+internal fun IdentityDataEntity.Companion.setHashDetails(
+        realm: Realm,
+        pepper: String,
+        algorithms: List<String>
+) {
     get(realm)?.apply {
         hashLookupPepper = pepper
         hashLookupAlgorithm = RealmList<String>().apply { addAll(algorithms) }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/Extensions.kt
deleted file mode 100644
index b40b1a56bfefd4c1a81271ef36477386b3129c95..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/Extensions.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2021 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.initsync
-
-import org.matrix.android.sdk.api.session.initsync.InitSyncStep
-
-internal inline fun <T> reportSubtask(reporter: ProgressReporter?,
-                                      initSyncStep: InitSyncStep,
-                                      totalProgress: Int,
-                                      parentWeight: Float,
-                                      block: () -> T): T {
-    reporter?.startTask(initSyncStep, totalProgress, parentWeight)
-    return block().also {
-        reporter?.endTask()
-    }
-}
-
-internal inline fun <K, V, R> Map<out K, V>.mapWithProgress(reporter: ProgressReporter?,
-                                                            initSyncStep: InitSyncStep,
-                                                            parentWeight: Float,
-                                                            transform: (Map.Entry<K, V>) -> R): List<R> {
-    var current = 0F
-    reporter?.startTask(initSyncStep, count() + 1, parentWeight)
-    return map {
-        reporter?.reportProgress(current)
-        current++
-        transform.invoke(it)
-    }.also {
-        reporter?.endTask()
-    }
-}
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 8034e5b9740632b1df5b272fa6fd44588300ef8a..7588037b46aafaf1069112f83e5873ff27bcd77f 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
@@ -54,11 +54,13 @@ import javax.inject.Inject
  *
  */
 @SessionScope
-internal class IntegrationManager @Inject constructor(matrixConfiguration: MatrixConfiguration,
-                                                      @SessionDatabase private val monarchy: Monarchy,
-                                                      private val updateUserAccountDataTask: UpdateUserAccountDataTask,
-                                                      private val accountDataDataSource: UserAccountDataDataSource,
-                                                      private val widgetFactory: WidgetFactory) :
+internal class IntegrationManager @Inject constructor(
+        matrixConfiguration: MatrixConfiguration,
+        @SessionDatabase private val monarchy: Monarchy,
+        private val updateUserAccountDataTask: UpdateUserAccountDataTask,
+        private val accountDataDataSource: UserAccountDataDataSource,
+        private val widgetFactory: WidgetFactory
+) :
         SessionLifecycleObserver {
 
     private val currentConfigs = ArrayList<IntegrationManagerConfig>()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt
index 32bcf3f7ca8e6c36d682bcea3067c7d56649d73b..a31f0d606553ee9ad06b28905a2e5fc324bbe70f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt
@@ -48,8 +48,8 @@ internal class DefaultGetPreviewUrlTask @Inject constructor(
 
     override suspend fun execute(params: GetPreviewUrlTask.Params): PreviewUrlData {
         return when (params.cacheStrategy) {
-            CacheStrategy.NoCache       -> doRequest(params.url, params.timestamp)
-            is CacheStrategy.TtlCache   -> doRequestWithCache(
+            CacheStrategy.NoCache -> doRequest(params.url, params.timestamp)
+            is CacheStrategy.TtlCache -> doRequestWithCache(
                     params.url,
                     params.timestamp,
                     params.cacheStrategy.validityDurationInMillis,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt
index a6ad025b8d769301d58ede89a545daf15410c2ec..5ab6aca88c75a0b17643645fc5884868fece08b1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt
@@ -28,7 +28,8 @@ internal interface GetOpenIdTokenTask : Task<Unit, OpenIdToken>
 internal class DefaultGetOpenIdTokenTask @Inject constructor(
         @UserId private val userId: String,
         private val openIdAPI: OpenIdAPI,
-        private val globalErrorReceiver: GlobalErrorReceiver) : GetOpenIdTokenTask {
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : GetOpenIdTokenTask {
 
     override suspend fun execute(params: Unit): OpenIdToken {
         return executeRequest(globalErrorReceiver) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/OpenIdAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/OpenIdAPI.kt
index eb8c841d5771afb2c656d3a962842429628e3508..180ecbb1a3147ec94efac9b1c2d31986885bde0e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/OpenIdAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/OpenIdAPI.kt
@@ -32,8 +32,11 @@ internal interface OpenIdAPI {
      * Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-user-userid-openid-request-token
      *
      * @param userId the user id
+     * @param body an empty json body
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/openid/request_token")
-    suspend fun openIdToken(@Path("userId") userId: String,
-                            @Body body: JsonDict = emptyMap()): OpenIdToken
+    suspend fun openIdToken(
+            @Path("userId") userId: String,
+            @Body body: JsonDict = emptyMap()
+    ): OpenIdToken
 }
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 f9da7b66f623ff96a116637bc69697ab0fa5bd9a..8e20199135a336d6a43e5edbf670370cc1e12706 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
@@ -44,15 +44,15 @@ internal class PermalinkFactory @Inject constructor(
 
     fun createPermalink(id: String, forceMatrixTo: Boolean): String? {
         return when {
-            id.isEmpty()                    -> null
+            id.isEmpty() -> null
             !useClientFormat(forceMatrixTo) -> MATRIX_TO_URL_BASE + escape(id)
-            else                            -> {
+            else -> {
                 buildString {
                     append(matrixConfiguration.clientPermalinkBaseUrl)
                     when {
                         MatrixPatterns.isRoomId(id) || MatrixPatterns.isRoomAlias(id) -> append(ROOM_PATH)
-                        MatrixPatterns.isUserId(id)                                   -> append(USER_PATH)
-                        MatrixPatterns.isGroupId(id)                                  -> append(GROUP_PATH)
+                        MatrixPatterns.isUserId(id) -> append(USER_PATH)
+                        MatrixPatterns.isGroupId(id) -> append(GROUP_PATH)
                     }
                     append(escape(id))
                 }
@@ -94,16 +94,16 @@ internal class PermalinkFactory @Inject constructor(
     fun getLinkedId(url: String): String? {
         val clientBaseUrl = matrixConfiguration.clientPermalinkBaseUrl
         return when {
-            url.startsWith(MATRIX_TO_URL_BASE)                     -> url.substring(MATRIX_TO_URL_BASE.length)
+            url.startsWith(MATRIX_TO_URL_BASE) -> url.substring(MATRIX_TO_URL_BASE.length)
             clientBaseUrl != null && url.startsWith(clientBaseUrl) -> {
                 when (PermalinkParser.parse(url)) {
                     is PermalinkData.GroupLink -> url.substring(clientBaseUrl.length + GROUP_PATH.length)
-                    is PermalinkData.RoomLink  -> url.substring(clientBaseUrl.length + ROOM_PATH.length)
-                    is PermalinkData.UserLink  -> url.substring(clientBaseUrl.length + USER_PATH.length)
-                    else                       -> null
+                    is PermalinkData.RoomLink -> url.substring(clientBaseUrl.length + ROOM_PATH.length)
+                    is PermalinkData.UserLink -> url.substring(clientBaseUrl.length + USER_PATH.length)
+                    else -> null
                 }
             }
-            else                                                   -> null
+            else -> null
         }
                 ?.substringBeforeLast("?")
     }
@@ -111,7 +111,7 @@ internal class PermalinkFactory @Inject constructor(
     fun createMentionSpanTemplate(type: PermalinkService.SpanTemplateType, forceMatrixTo: Boolean): String {
         return buildString {
             when (type) {
-                HTML     -> append(MENTION_SPAN_TO_HTML_TEMPLATE_BEGIN)
+                HTML -> append(MENTION_SPAN_TO_HTML_TEMPLATE_BEGIN)
                 MARKDOWN -> append(MENTION_SPAN_TO_MD_TEMPLATE_BEGIN)
             }
             append(baseUrl(forceMatrixTo))
@@ -119,7 +119,7 @@ internal class PermalinkFactory @Inject constructor(
                 append(USER_PATH)
             }
             when (type) {
-                HTML     -> append(MENTION_SPAN_TO_HTML_TEMPLATE_END)
+                HTML -> append(MENTION_SPAN_TO_HTML_TEMPLATE_END)
                 MARKDOWN -> append(MENTION_SPAN_TO_MD_TEMPLATE_END)
             }
         }
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 0f667c65df7562390eeab67ac24f37c19c56edd3..edc45fe94549b839c2e0b8096af61d38d539aaea 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
@@ -16,7 +16,7 @@
 
 package org.matrix.android.sdk.internal.session.permalinks
 
-import org.matrix.android.sdk.api.MatrixPatterns.getDomain
+import org.matrix.android.sdk.api.MatrixPatterns.getServerName
 import org.matrix.android.sdk.api.query.QueryStringValue
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.toModel
@@ -55,9 +55,9 @@ internal class ViaParameterFinder @Inject constructor(
     }
 
     fun computeViaParams(userId: String, roomId: String, max: Int): List<String> {
-        val userHomeserver = userId.getDomain()
+        val userHomeserver = userId.getServerName()
         return getUserIdsOfJoinedMembers(roomId)
-                .map { it.getDomain() }
+                .map { it.getServerName() }
                 .groupBy { it }
                 .mapValues { it.value.size }
                 .toMutableMap()
@@ -92,7 +92,7 @@ internal class ViaParameterFinder @Inject constructor(
                 .orEmpty()
                 .toSet()
 
-        return userThatCanInvite.map { it.getDomain() }
+        return userThatCanInvite.map { it.getServerName() }
                 .groupBy { it }
                 .mapValues { it.value.size }
                 .toMutableMap()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/PresenceAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/PresenceAPI.kt
index 53d0d5e9631e8f7599545cc272e22e8866b48574..4af0307cb5eb95f0752a419f21190e414c6e3c09 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/PresenceAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/PresenceAPI.kt
@@ -31,8 +31,10 @@ internal interface PresenceAPI {
      * Ref: https://matrix.org/docs/spec/client_server/latest#put-matrix-client-r0-presence-userid-status
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "presence/{userId}/status")
-    suspend fun setPresence(@Path("userId") userId: String,
-                            @Body body: SetPresenceBody)
+    suspend fun setPresence(
+            @Path("userId") userId: String,
+            @Body body: SetPresenceBody
+    )
 
     /**
      * Get the given user's presence state.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt
index 678d3994284c65dccdc033e9aeebeab2a6900447..4a6cb6c019cebc7b099fca98285c8de8dd3d13ff 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt
@@ -37,11 +37,12 @@ internal class DefaultAddThreePidTask @Inject constructor(
         private val profileAPI: ProfileAPI,
         @SessionDatabase private val monarchy: Monarchy,
         private val pendingThreePidMapper: PendingThreePidMapper,
-        private val globalErrorReceiver: GlobalErrorReceiver) : AddThreePidTask() {
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : AddThreePidTask() {
 
     override suspend fun execute(params: Params) {
         when (params.threePid) {
-            is ThreePid.Email  -> addEmail(params.threePid)
+            is ThreePid.Email -> addEmail(params.threePid)
             is ThreePid.Msisdn -> addMsisdn(params.threePid)
         }
     }
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 f630c2c225fc355106eb018adb2ddb49d177f798..5e892b32c3c8c8ad915b55e83261ec4d5a7813af 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
@@ -33,11 +33,12 @@ internal abstract class BindThreePidsTask : Task<BindThreePidsTask.Params, Unit>
     )
 }
 
-internal class DefaultBindThreePidsTask @Inject constructor(private val profileAPI: ProfileAPI,
-                                                            private val identityStore: IdentityStore,
-                                                            @AuthenticatedIdentity
-                                                            private val accessTokenProvider: AccessTokenProvider,
-                                                            private val globalErrorReceiver: GlobalErrorReceiver) : BindThreePidsTask() {
+internal class DefaultBindThreePidsTask @Inject constructor(
+        private val profileAPI: ProfileAPI,
+        private val identityStore: IdentityStore,
+        @AuthenticatedIdentity private val accessTokenProvider: AccessTokenProvider,
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : BindThreePidsTask() {
     override suspend fun execute(params: Params) {
         val identityServerUrlWithoutProtocol = identityStore.getIdentityServerUrlWithoutProtocol() ?: throw IdentityServiceError.NoIdentityServerConfigured
         val identityServerAccessToken = accessTokenProvider.getToken() ?: throw IdentityServiceError.NoIdentityServerConfigured
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 5e64a6af0e2bc568989b4c75eab6ca892be9afa9..07765696619152693107ecaf1935ae108286f098 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
@@ -38,20 +38,22 @@ import org.matrix.android.sdk.internal.task.TaskExecutor
 import org.matrix.android.sdk.internal.task.configureWith
 import javax.inject.Inject
 
-internal class DefaultProfileService @Inject constructor(private val taskExecutor: TaskExecutor,
-                                                         @SessionDatabase private val monarchy: Monarchy,
-                                                         private val coroutineDispatchers: MatrixCoroutineDispatchers,
-                                                         private val refreshUserThreePidsTask: RefreshUserThreePidsTask,
-                                                         private val getProfileInfoTask: GetProfileInfoTask,
-                                                         private val setDisplayNameTask: SetDisplayNameTask,
-                                                         private val setAvatarUrlTask: SetAvatarUrlTask,
-                                                         private val addThreePidTask: AddThreePidTask,
-                                                         private val validateSmsCodeTask: ValidateSmsCodeTask,
-                                                         private val finalizeAddingThreePidTask: FinalizeAddingThreePidTask,
-                                                         private val deleteThreePidTask: DeleteThreePidTask,
-                                                         private val pendingThreePidMapper: PendingThreePidMapper,
-                                                         private val userStore: UserStore,
-                                                         private val fileUploader: FileUploader) : ProfileService {
+internal class DefaultProfileService @Inject constructor(
+        private val taskExecutor: TaskExecutor,
+        @SessionDatabase private val monarchy: Monarchy,
+        private val coroutineDispatchers: MatrixCoroutineDispatchers,
+        private val refreshUserThreePidsTask: RefreshUserThreePidsTask,
+        private val getProfileInfoTask: GetProfileInfoTask,
+        private val setDisplayNameTask: SetDisplayNameTask,
+        private val setAvatarUrlTask: SetAvatarUrlTask,
+        private val addThreePidTask: AddThreePidTask,
+        private val validateSmsCodeTask: ValidateSmsCodeTask,
+        private val finalizeAddingThreePidTask: FinalizeAddingThreePidTask,
+        private val deleteThreePidTask: DeleteThreePidTask,
+        private val pendingThreePidMapper: PendingThreePidMapper,
+        private val userStore: UserStore,
+        private val fileUploader: FileUploader
+) : ProfileService {
 
     override suspend fun getDisplayName(userId: String): Optional<String> {
         val params = GetProfileInfoTask.Params(userId)
@@ -132,8 +134,10 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
         validateSmsCodeTask.execute(ValidateSmsCodeTask.Params(threePid, code))
     }
 
-    override suspend fun finalizeAddingThreePid(threePid: ThreePid,
-                                                userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) {
+    override suspend fun finalizeAddingThreePid(
+            threePid: ThreePid,
+            userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor
+    ) {
         finalizeAddingThreePidTask
                 .execute(
                         FinalizeAddingThreePidTask.Params(
@@ -165,8 +169,8 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
 
 private fun UserThreePidEntity.asDomain(): ThreePid {
     return when (medium) {
-        ThirdPartyIdentifier.MEDIUM_EMAIL  -> ThreePid.Email(address)
+        ThirdPartyIdentifier.MEDIUM_EMAIL -> ThreePid.Email(address)
         ThirdPartyIdentifier.MEDIUM_MSISDN -> ThreePid.Msisdn(address)
-        else                               -> error("Invalid medium type")
+        else -> error("Invalid medium type")
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt
index 7b7617aa8094906b8f453aef4066082aea354d3e..a8047a0118f0786f5758f503ba1d170d4365b6e0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt
@@ -31,7 +31,8 @@ internal abstract class DeleteThreePidTask : Task<DeleteThreePidTask.Params, Uni
 
 internal class DefaultDeleteThreePidTask @Inject constructor(
         private val profileAPI: ProfileAPI,
-        private val globalErrorReceiver: GlobalErrorReceiver) : DeleteThreePidTask() {
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : DeleteThreePidTask() {
 
     override suspend fun execute(params: Params) {
         val body = DeleteThreePidBody(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt
index 501aff63bd91b11c6455b270552198a9046081d6..89fcbca1ca64b18a8e8d403aaa23db86a35167d7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt
@@ -47,7 +47,8 @@ internal class DefaultFinalizeAddingThreePidTask @Inject constructor(
         private val profileAPI: ProfileAPI,
         @SessionDatabase private val monarchy: Monarchy,
         private val pendingThreePidMapper: PendingThreePidMapper,
-        private val globalErrorReceiver: GlobalErrorReceiver) : FinalizeAddingThreePidTask() {
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : FinalizeAddingThreePidTask() {
 
     override suspend fun execute(params: Params) {
         val canCleanup = if (params.userWantsToCancel) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/GetProfileInfoTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/GetProfileInfoTask.kt
index fed4288f849e0bae23f7da2f0a7e7d58d5ebabcd..40444edcab33143960c56678f460e7b6cffd875a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/GetProfileInfoTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/GetProfileInfoTask.kt
@@ -29,8 +29,10 @@ internal abstract class GetProfileInfoTask : Task<GetProfileInfoTask.Params, Jso
     )
 }
 
-internal class DefaultGetProfileInfoTask @Inject constructor(private val profileAPI: ProfileAPI,
-                                                             private val globalErrorReceiver: GlobalErrorReceiver) : GetProfileInfoTask() {
+internal class DefaultGetProfileInfoTask @Inject constructor(
+        private val profileAPI: ProfileAPI,
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : GetProfileInfoTask() {
 
     override suspend fun execute(params: Params): JsonDict {
         return executeRequest(globalErrorReceiver) {
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 4d4506be76785f2d3365cabfd3848ad6c7f51d94..aa7f21d332ac28aec40a63d87e726d274fdfaa0e 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
@@ -49,15 +49,19 @@ internal interface ProfileAPI {
      * Change user display name.
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}/displayname")
-    suspend fun setDisplayName(@Path("userId") userId: String,
-                               @Body body: SetDisplayNameBody)
+    suspend fun setDisplayName(
+            @Path("userId") userId: String,
+            @Body body: SetDisplayNameBody
+    )
 
     /**
      * Change user avatar url.
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}/avatar_url")
-    suspend fun setAvatarUrl(@Path("userId") userId: String,
-                             @Body body: SetAvatarUrlBody)
+    suspend fun setAvatarUrl(
+            @Path("userId") userId: String,
+            @Body body: SetAvatarUrlBody
+    )
 
     /**
      * Bind a threePid
@@ -89,8 +93,10 @@ internal interface ProfileAPI {
      * Validate Msisdn code (same model than for identity server API).
      */
     @POST
-    suspend fun validateMsisdn(@Url url: String,
-                               @Body params: ValidationCodeBody): SuccessResult
+    suspend fun validateMsisdn(
+            @Url url: String,
+            @Body params: ValidationCodeBody
+    ): SuccessResult
 
     /**
      * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-3pid-add
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/RefreshUserThreePidsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/RefreshUserThreePidsTask.kt
index 8a064b4fd12c93d98e70e0b7ffb8e19d3b03db76..8a25d870b67bd1f49d74433550c8236e24404282 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/RefreshUserThreePidsTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/RefreshUserThreePidsTask.kt
@@ -28,9 +28,11 @@ import javax.inject.Inject
 
 internal abstract class RefreshUserThreePidsTask : Task<Unit, Unit>
 
-internal class DefaultRefreshUserThreePidsTask @Inject constructor(private val profileAPI: ProfileAPI,
-                                                                   @SessionDatabase private val monarchy: Monarchy,
-                                                                   private val globalErrorReceiver: GlobalErrorReceiver) : RefreshUserThreePidsTask() {
+internal class DefaultRefreshUserThreePidsTask @Inject constructor(
+        private val profileAPI: ProfileAPI,
+        @SessionDatabase private val monarchy: Monarchy,
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : RefreshUserThreePidsTask() {
 
     override suspend fun execute(params: Unit) {
         val accountThreePidsResponse = executeRequest(globalErrorReceiver) {
@@ -55,9 +57,9 @@ internal class DefaultRefreshUserThreePidsTask @Inject constructor(private val p
 
 private fun Any?.toLong(): Long {
     return when (this) {
-        null      -> 0L
-        is Long   -> this
+        null -> 0L
+        is Long -> this
         is Double -> this.toLong()
-        else      -> 0L
+        else -> 0L
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetAvatarUrlTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetAvatarUrlTask.kt
index a7d116d919df94c6a64fc71f31abba8011f5df17..80282a894b17e426d048bad6c68f51fcf3db7d29 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetAvatarUrlTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetAvatarUrlTask.kt
@@ -30,7 +30,8 @@ internal abstract class SetAvatarUrlTask : Task<SetAvatarUrlTask.Params, Unit> {
 
 internal class DefaultSetAvatarUrlTask @Inject constructor(
         private val profileAPI: ProfileAPI,
-        private val globalErrorReceiver: GlobalErrorReceiver) : SetAvatarUrlTask() {
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : SetAvatarUrlTask() {
 
     override suspend fun execute(params: Params) {
         val body = SetAvatarUrlBody(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetDisplayNameTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetDisplayNameTask.kt
index 61d304231038a889a6f8ce5422d0029712ef7ea0..e3f04792b63464648aedcfcc94872335e25b8d0d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetDisplayNameTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetDisplayNameTask.kt
@@ -30,7 +30,8 @@ internal abstract class SetDisplayNameTask : Task<SetDisplayNameTask.Params, Uni
 
 internal class DefaultSetDisplayNameTask @Inject constructor(
         private val profileAPI: ProfileAPI,
-        private val globalErrorReceiver: GlobalErrorReceiver) : SetDisplayNameTask() {
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : SetDisplayNameTask() {
 
     override suspend fun execute(params: Params) {
         val body = SetDisplayNameBody(
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 acbecc9fbee766050e12bf6f5815eef7eddd6cc2..2e2eb65bd41e8502e298d3270a9fc9c7bf796ace 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
@@ -32,9 +32,11 @@ internal abstract class UnbindThreePidsTask : Task<UnbindThreePidsTask.Params, B
     )
 }
 
-internal class DefaultUnbindThreePidsTask @Inject constructor(private val profileAPI: ProfileAPI,
-                                                              private val identityStore: IdentityStore,
-                                                              private val globalErrorReceiver: GlobalErrorReceiver) : UnbindThreePidsTask() {
+internal class DefaultUnbindThreePidsTask @Inject constructor(
+        private val profileAPI: ProfileAPI,
+        private val identityStore: IdentityStore,
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : UnbindThreePidsTask() {
     override suspend fun execute(params: Params): Boolean {
         val identityServerUrlWithoutProtocol = identityStore.getIdentityServerUrlWithoutProtocol()
                 ?: throw IdentityServiceError.NoIdentityServerConfigured
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPusherWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPusherWorker.kt
index 0042558027746ef4422dd337825a27c21aeb083b..5fd50f175243878f63f35267a5d5acc8803e9595 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPusherWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPusherWorker.kt
@@ -53,7 +53,7 @@ internal class AddPusherWorker(context: Context, params: WorkerParameters, sessi
         } catch (exception: Throwable) {
             when (exception) {
                 is Failure.NetworkConnection -> Result.retry()
-                else                         -> Result.failure()
+                else -> Result.failure()
             }
         }
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultConditionResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultConditionResolver.kt
index 67fba390d00e1a5458060f005678a20a382fd047..ace5ee0b9a17d0448e8243deed3f27dfcc83d02d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultConditionResolver.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultConditionResolver.kt
@@ -34,18 +34,24 @@ internal class DefaultConditionResolver @Inject constructor(
         @UserId private val userId: String
 ) : ConditionResolver {
 
-    override fun resolveEventMatchCondition(event: Event,
-                                            condition: EventMatchCondition): Boolean {
+    override fun resolveEventMatchCondition(
+            event: Event,
+            condition: EventMatchCondition
+    ): Boolean {
         return condition.isSatisfied(event)
     }
 
-    override fun resolveRoomMemberCountCondition(event: Event,
-                                                 condition: RoomMemberCountCondition): Boolean {
+    override fun resolveRoomMemberCountCondition(
+            event: Event,
+            condition: RoomMemberCountCondition
+    ): Boolean {
         return condition.isSatisfied(event, roomGetter)
     }
 
-    override fun resolveSenderNotificationPermissionCondition(event: Event,
-                                                              condition: SenderNotificationPermissionCondition): Boolean {
+    override fun resolveSenderNotificationPermissionCondition(
+            event: Event,
+            condition: SenderNotificationPermissionCondition
+    ): Boolean {
         val roomId = event.roomId ?: return false
         val room = roomGetter.getRoom(roomId) ?: return false
 
@@ -57,8 +63,10 @@ internal class DefaultConditionResolver @Inject constructor(
         return condition.isSatisfied(event, powerLevelsContent)
     }
 
-    override fun resolveContainsDisplayNameCondition(event: Event,
-                                                     condition: ContainsDisplayNameCondition): Boolean {
+    override fun resolveContainsDisplayNameCondition(
+            event: Event,
+            condition: ContainsDisplayNameCondition
+    ): Boolean {
         val roomId = event.roomId ?: return false
         val room = roomGetter.getRoom(roomId) ?: return false
         val myDisplayName = room.membershipService().getRoomMember(userId)?.displayName ?: return false
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 13b990a9ff5baeb0135c634d9ed156726535d7a8..e912d9ccf888986f31ea4fefd934224c84e2c192 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
@@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.pushers
 import androidx.lifecycle.LiveData
 import androidx.work.BackoffPolicy
 import com.zhuinden.monarchy.Monarchy
+import org.matrix.android.sdk.api.session.pushers.HttpPusher
 import org.matrix.android.sdk.api.session.pushers.Pusher
 import org.matrix.android.sdk.api.session.pushers.PushersService
 import org.matrix.android.sdk.internal.database.mapper.asDomain
@@ -45,10 +46,12 @@ internal class DefaultPushersService @Inject constructor(
         private val taskExecutor: TaskExecutor
 ) : PushersService {
 
-    override suspend fun testPush(url: String,
-                                  appId: String,
-                                  pushkey: String,
-                                  eventId: String) {
+    override suspend fun testPush(
+            url: String,
+            appId: String,
+            pushkey: String,
+            eventId: String
+    ) {
         pushGatewayNotifyTask.execute(PushGatewayNotifyTask.Params(url, appId, pushkey, eventId))
     }
 
@@ -58,15 +61,15 @@ internal class DefaultPushersService @Inject constructor(
                 .executeBy(taskExecutor)
     }
 
-    override fun enqueueAddHttpPusher(httpPusher: PushersService.HttpPusher): UUID {
+    override fun enqueueAddHttpPusher(httpPusher: HttpPusher): UUID {
         return enqueueAddPusher(httpPusher.toJsonPusher())
     }
 
-    override suspend fun addHttpPusher(httpPusher: PushersService.HttpPusher) {
+    override suspend fun addHttpPusher(httpPusher: HttpPusher) {
         addPusherTask.execute(AddPusherTask.Params(httpPusher.toJsonPusher()))
     }
 
-    private fun PushersService.HttpPusher.toJsonPusher() = JsonPusher(
+    private fun HttpPusher.toJsonPusher() = JsonPusher(
             pushKey = pushkey,
             kind = "http",
             appId = appId,
@@ -78,12 +81,14 @@ internal class DefaultPushersService @Inject constructor(
             append = append
     )
 
-    override suspend fun addEmailPusher(email: String,
-                                        lang: String,
-                                        emailBranding: String,
-                                        appDisplayName: String,
-                                        deviceDisplayName: String,
-                                        append: Boolean) {
+    override suspend fun addEmailPusher(
+            email: String,
+            lang: String,
+            emailBranding: String,
+            appDisplayName: String,
+            deviceDisplayName: String,
+            append: Boolean
+    ) {
         addPusherTask.execute(
                 AddPusherTask.Params(
                         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 40b4ee269ac8b3d82318f5c6c1e52af2438be1b1..1b316c78728c11bfb6dec813a7e9e984f3247d1d 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
@@ -33,47 +33,55 @@ internal interface PushRulesApi {
     /**
      * Update the ruleID enable status.
      *
-     * @param kind   the notification kind (sender, room...)
+     * @param kind the notification kind (sender, room...)
      * @param ruleId the ruleId
-     * @param enable the new enable status
+     * @param enabledBody the new enable status
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}/enabled")
-    suspend fun updateEnableRuleStatus(@Path("kind") kind: String,
-                                       @Path("ruleId") ruleId: String,
-                                       @Body enabledBody: EnabledBody)
+    suspend fun updateEnableRuleStatus(
+            @Path("kind") kind: String,
+            @Path("ruleId") ruleId: String,
+            @Body enabledBody: EnabledBody
+    )
 
     /**
      * 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...)
-     * @param ruleId  the ruleId
+     * @param kind the notification kind (sender, room...)
+     * @param ruleId the ruleId
      * @param actions the actions
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}/actions")
-    suspend fun updateRuleActions(@Path("kind") kind: String,
-                                  @Path("ruleId") ruleId: String,
-                                  @Body actions: Any)
+    suspend fun updateRuleActions(
+            @Path("kind") kind: String,
+            @Path("ruleId") ruleId: String,
+            @Body actions: Any
+    )
 
     /**
      * Delete a rule.
      *
-     * @param kind   the notification kind (sender, room...)
+     * @param kind the notification kind (sender, room...)
      * @param ruleId the ruleId
      */
     @DELETE(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}")
-    suspend fun deleteRule(@Path("kind") kind: String,
-                           @Path("ruleId") ruleId: String)
+    suspend fun deleteRule(
+            @Path("kind") kind: String,
+            @Path("ruleId") ruleId: String
+    )
 
     /**
      * Add the ruleID enable status.
      *
-     * @param kind   the notification kind (sender, room...)
+     * @param kind the notification kind (sender, room...)
      * @param ruleId the ruleId.
-     * @param rule   the rule to add.
+     * @param rule the rule to add.
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}")
-    suspend fun addRule(@Path("kind") kind: String,
-                        @Path("ruleId") ruleId: String,
-                        @Body rule: PushRule)
+    suspend fun addRule(
+            @Path("kind") kind: String,
+            @Path("ruleId") ruleId: String,
+            @Body rule: PushRule
+    )
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePusherTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePusherTask.kt
index 057c309078586c4980eb1e6cda71026fb6c8533e..86ba33cb98e9c2485ffbd1ef335514564110e72f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePusherTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePusherTask.kt
@@ -30,8 +30,10 @@ import org.matrix.android.sdk.internal.util.awaitTransaction
 import javax.inject.Inject
 
 internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> {
-    data class Params(val pushKey: String,
-                      val pushAppId: String)
+    data class Params(
+            val pushKey: String,
+            val pushAppId: String
+    )
 }
 
 internal class DefaultRemovePusherTask @Inject constructor(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt
index 815661a1ce9863170b2d10e29ee6aa120f8b1d9c..a923f1932b3813795198860e10f40b88d1b1ff9d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt
@@ -23,9 +23,11 @@ import org.matrix.android.sdk.internal.task.Task
 import javax.inject.Inject
 
 internal interface UpdatePushRuleEnableStatusTask : Task<UpdatePushRuleEnableStatusTask.Params, Unit> {
-    data class Params(val kind: RuleKind,
-                      val pushRule: PushRule,
-                      val enabled: Boolean)
+    data class Params(
+            val kind: RuleKind,
+            val pushRule: PushRule,
+            val enabled: Boolean
+    )
 }
 
 internal class DefaultUpdatePushRuleEnableStatusTask @Inject constructor(
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 60c1194708307859e2060ae2d42251f8d540d042..09d7d50ecb86091eb0d2bdfa20f59e1f2bf7282b 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
@@ -62,7 +62,7 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
                 EventType.REDACTION,
                 EventType.ENCRYPTED,
                 EventType.STATE_ROOM_MEMBER -> true
-                else                        -> false
+                else -> false
             }
         }.filter {
             it.senderId != userId
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt
index 7326adee4c7a1a1d68ad1a3283046c57f3056606..abea2d34cd210834c680d81dc819b5346ecaf17a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt
@@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataServic
 import org.matrix.android.sdk.api.session.room.alias.AliasService
 import org.matrix.android.sdk.api.session.room.call.RoomCallService
 import org.matrix.android.sdk.api.session.room.crypto.RoomCryptoService
+import org.matrix.android.sdk.api.session.room.location.LocationSharingService
 import org.matrix.android.sdk.api.session.room.members.MembershipService
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.api.session.room.model.RoomType
@@ -69,6 +70,7 @@ internal class DefaultRoom(
         private val roomAccountDataService: RoomAccountDataService,
         private val roomVersionService: RoomVersionService,
         private val viaParameterFinder: ViaParameterFinder,
+        private val locationSharingService: LocationSharingService,
         override val coroutineDispatchers: MatrixCoroutineDispatchers
 ) : Room {
 
@@ -104,4 +106,5 @@ internal class DefaultRoom(
     override fun roomPushRuleService() = roomPushRuleService
     override fun roomAccountDataService() = roomAccountDataService
     override fun roomVersionService() = roomVersionService
+    override fun locationSharingService() = locationSharingService
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt
index 7330c91c202d0f088f87b7bbcaf0217e98369292..1edc4c1e66ea5059cfcce384e0b4c57ea450adea 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt
@@ -35,8 +35,10 @@ internal class DefaultRoomDirectoryService @Inject constructor(
         private val roomAliasAvailabilityChecker: RoomAliasAvailabilityChecker
 ) : RoomDirectoryService {
 
-    override suspend fun getPublicRooms(server: String?,
-                                        publicRoomsParams: PublicRoomsParams): PublicRoomsResponse {
+    override suspend fun getPublicRooms(
+            server: String?,
+            publicRoomsParams: PublicRoomsParams
+    ): PublicRoomsResponse {
         return getPublicRoomTask.execute(GetPublicRoomTask.Params(server, publicRoomsParams))
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt
index 8424ee8a36384a5ea91e8c223f2f958fd67b589e..5e6d052443d0c54b0742eaf3f12692bf51592d74 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt
@@ -20,7 +20,6 @@ import androidx.lifecycle.LiveData
 import androidx.lifecycle.Transformations
 import androidx.paging.PagedList
 import com.zhuinden.monarchy.Monarchy
-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.identity.model.SignInvitationResult
 import org.matrix.android.sdk.api.session.room.Room
@@ -91,18 +90,27 @@ internal class DefaultRoomService @Inject constructor(
         return roomSummaryDataSource.getRoomSummary(roomIdOrAlias)
     }
 
-    override fun getRoomSummaries(queryParams: RoomSummaryQueryParams,
-                                  sortOrder: RoomSortOrder): List<RoomSummary> {
+    override fun getRoomSummaryLive(roomId: String): LiveData<Optional<RoomSummary>> {
+        return roomSummaryDataSource.getRoomSummaryLive(roomId)
+    }
+
+    override fun getRoomSummaries(
+            queryParams: RoomSummaryQueryParams,
+            sortOrder: RoomSortOrder
+    ): List<RoomSummary> {
         return roomSummaryDataSource.getRoomSummaries(queryParams, sortOrder)
     }
 
     override fun refreshJoinedRoomSummaryPreviews(roomId: String?) {
-        val roomSummaries = getRoomSummaries(roomSummaryQueryParams {
-            if (roomId != null) {
-                this.roomId = QueryStringValue.Equals(roomId)
-            }
-            memberships = listOf(Membership.JOIN)
-        })
+        val roomSummaries = if (roomId == null) {
+            getRoomSummaries(roomSummaryQueryParams {
+                memberships = listOf(Membership.JOIN)
+            })
+        } else {
+            listOfNotNull(
+                    getRoomSummary(roomId)?.takeIf { it.membership == Membership.JOIN }
+            )
+        }
 
         if (roomSummaries.isNotEmpty()) {
             monarchy.runTransactionSync { realm ->
@@ -113,21 +121,28 @@ internal class DefaultRoomService @Inject constructor(
         }
     }
 
-    override fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams,
-                                      sortOrder: RoomSortOrder): LiveData<List<RoomSummary>> {
+    override fun getRoomSummariesLive(
+            queryParams: RoomSummaryQueryParams,
+            sortOrder: RoomSortOrder
+    ): LiveData<List<RoomSummary>> {
         return roomSummaryDataSource.getRoomSummariesLive(queryParams, sortOrder)
     }
 
-    override fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
-                                           pagedListConfig: PagedList.Config,
-                                           sortOrder: RoomSortOrder): LiveData<PagedList<RoomSummary>> {
+    override fun getPagedRoomSummariesLive(
+            queryParams: RoomSummaryQueryParams,
+            pagedListConfig: PagedList.Config,
+            sortOrder: RoomSortOrder
+    ): LiveData<PagedList<RoomSummary>> {
         return roomSummaryDataSource.getSortedPagedRoomSummariesLive(queryParams, pagedListConfig, sortOrder)
     }
 
-    override fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
-                                                   pagedListConfig: PagedList.Config,
-                                                   sortOrder: RoomSortOrder): UpdatableLivePageResult {
-        return roomSummaryDataSource.getUpdatablePagedRoomSummariesLive(queryParams, pagedListConfig, sortOrder)
+    override fun getFilteredPagedRoomSummariesLive(
+            queryParams: RoomSummaryQueryParams,
+            pagedListConfig: PagedList.Config,
+            sortOrder: RoomSortOrder,
+            getFlattenParents: Boolean
+    ): UpdatableLivePageResult {
+        return roomSummaryDataSource.getUpdatablePagedRoomSummariesLive(queryParams, pagedListConfig, sortOrder, getFlattenParents)
     }
 
     override fun getRoomCountLive(queryParams: RoomSummaryQueryParams): LiveData<Int> {
@@ -154,9 +169,11 @@ internal class DefaultRoomService @Inject constructor(
         joinRoomTask.execute(JoinRoomTask.Params(roomIdOrAlias, reason, viaServers))
     }
 
-    override suspend fun joinRoom(roomId: String,
-                                  reason: String?,
-                                  thirdPartySigned: SignInvitationResult) {
+    override suspend fun joinRoom(
+            roomId: String,
+            reason: String?,
+            thirdPartySigned: SignInvitationResult
+    ) {
         joinRoomTask.execute(JoinRoomTask.Params(roomId, reason, thirdPartySigned = thirdPartySigned))
     }
 
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 16a63a9a96afb152dee055d4b9e3cb74ae5473dc..bb43d90328b90c4b4b6cb9b9865e0df55bf4aa44 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
@@ -16,7 +16,6 @@
 package org.matrix.android.sdk.internal.session.room
 
 import io.realm.Realm
-import org.matrix.android.sdk.api.extensions.orFalse
 import org.matrix.android.sdk.api.query.QueryStringValue
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationState
 import org.matrix.android.sdk.api.session.events.model.AggregatedAnnotation
@@ -28,23 +27,16 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventCon
 import org.matrix.android.sdk.api.session.events.model.getRelationContent
 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.room.getTimelineEvent
-import org.matrix.android.sdk.api.session.room.model.PollSummaryContent
 import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
 import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent
-import org.matrix.android.sdk.api.session.room.model.VoteInfo
-import org.matrix.android.sdk.api.session.room.model.VoteSummary
 import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageContent
-import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent
 import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
 import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
 import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent
 import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
-import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
-import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
 import org.matrix.android.sdk.internal.SessionManager
 import org.matrix.android.sdk.internal.crypto.verification.toState
 import org.matrix.android.sdk.internal.database.helper.findRootThreadEvent
@@ -55,7 +47,6 @@ import org.matrix.android.sdk.internal.database.model.EditionOfEvent
 import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity
 import org.matrix.android.sdk.internal.database.model.EventEntity
 import org.matrix.android.sdk.internal.database.model.EventInsertType
-import org.matrix.android.sdk.internal.database.model.PollResponseAggregatedSummaryEntity
 import org.matrix.android.sdk.internal.database.model.ReactionAggregatedSummaryEntity
 import org.matrix.android.sdk.internal.database.model.ReactionAggregatedSummaryEntityFields
 import org.matrix.android.sdk.internal.database.model.ReferencesAggregatedSummaryEntity
@@ -68,6 +59,7 @@ import org.matrix.android.sdk.internal.di.SessionId
 import org.matrix.android.sdk.internal.di.UserId
 import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor
 import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.LiveLocationAggregationProcessor
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollAggregationProcessor
 import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
 import org.matrix.android.sdk.internal.util.time.Clock
 import timber.log.Timber
@@ -79,6 +71,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
         @SessionId private val sessionId: String,
         private val sessionManager: SessionManager,
         private val liveLocationAggregationProcessor: LiveLocationAggregationProcessor,
+        private val pollAggregationProcessor: PollAggregationProcessor,
         private val clock: Clock,
 ) : EventInsertLiveProcessor {
 
@@ -110,12 +103,12 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
             }
             val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "")
             when (event.type) {
-                EventType.REACTION                  -> {
+                EventType.REACTION -> {
                     // we got a reaction!!
                     Timber.v("###REACTION in room $roomId , reaction eventID ${event.eventId}")
                     handleReaction(realm, event, roomId, isLocalEcho)
                 }
-                EventType.MESSAGE                   -> {
+                EventType.MESSAGE -> {
                     if (event.unsignedData?.relations?.annotations != null) {
                         Timber.v("###REACTION Aggregation in room $roomId for event ${event.eventId}")
                         handleInitialAggregatedRelations(realm, event, roomId, event.unsignedData.relations.annotations)
@@ -141,7 +134,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
                 EventType.KEY_VERIFICATION_START,
                 EventType.KEY_VERIFICATION_MAC,
                 EventType.KEY_VERIFICATION_READY,
-                EventType.KEY_VERIFICATION_KEY      -> {
+                EventType.KEY_VERIFICATION_KEY -> {
                     Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
                     event.content.toModel<MessageRelationContent>()?.relatesTo?.let {
                         if (it.type == RelationType.REFERENCE && it.eventId != null) {
@@ -150,7 +143,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
                     }
                 }
 
-                EventType.ENCRYPTED                 -> {
+                EventType.ENCRYPTED -> {
                     // Relation type is in clear
                     val encryptedEventContent = event.content.toModel<EncryptedEventContent>()
                     if (encryptedEventContent?.relatesTo?.type == RelationType.REPLACE ||
@@ -162,9 +155,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
                                 // A replace!
                                 handleReplace(realm, event, it, roomId, isLocalEcho, encryptedEventContent.relatesTo.eventId)
                             } else if (event.getClearType() in EventType.POLL_RESPONSE) {
-                                event.getClearContent().toModel<MessagePollResponseContent>(catchError = true)?.let { pollResponseContent ->
-                                    Timber.v("###RESPONSE in room $roomId for event ${event.eventId}")
-                                    handleResponse(realm, event, pollResponseContent, roomId, isLocalEcho, encryptedEventContent.relatesTo.eventId)
+                                sessionManager.getSessionComponent(sessionId)?.session()?.let { session ->
+                                    pollAggregationProcessor.handlePollResponseEvent(session, realm, event)
                                 }
                             }
                         }
@@ -176,26 +168,28 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
                             EventType.KEY_VERIFICATION_START,
                             EventType.KEY_VERIFICATION_MAC,
                             EventType.KEY_VERIFICATION_READY,
-                            EventType.KEY_VERIFICATION_KEY    -> {
+                            EventType.KEY_VERIFICATION_KEY -> {
                                 Timber.v("## SAS REF in room $roomId for event ${event.eventId}")
                                 encryptedEventContent.relatesTo.eventId?.let {
                                     handleVerification(realm, event, roomId, isLocalEcho, it)
                                 }
                             }
-                            in EventType.POLL_RESPONSE        -> {
+                            in EventType.POLL_RESPONSE -> {
                                 event.getClearContent().toModel<MessagePollResponseContent>(catchError = true)?.let {
-                                    handleResponse(realm, event, it, roomId, isLocalEcho, event.getRelationContent()?.eventId)
+                                    sessionManager.getSessionComponent(sessionId)?.session()?.let { session ->
+                                        pollAggregationProcessor.handlePollResponseEvent(session, realm, event)
+                                    }
                                 }
                             }
-                            in EventType.POLL_END             -> {
-                                event.content.toModel<MessageEndPollContent>(catchError = true)?.let {
-                                    handleEndPoll(realm, event, it, roomId, isLocalEcho)
+                            in EventType.POLL_END -> {
+                                sessionManager.getSessionComponent(sessionId)?.session()?.let { session ->
+                                    getPowerLevelsHelper(event.roomId)?.let {
+                                        pollAggregationProcessor.handlePollEndEvent(session, it, realm, event)
+                                    }
                                 }
                             }
                             in EventType.BEACON_LOCATION_DATA -> {
-                                event.getClearContent().toModel<MessageBeaconLocationDataContent>(catchError = true)?.let {
-                                    liveLocationAggregationProcessor.handleBeaconLocationData(realm, event, it, roomId, isLocalEcho)
-                                }
+                                handleBeaconLocationData(event, realm, roomId, isLocalEcho)
                             }
                         }
                     } else if (encryptedEventContent?.relatesTo?.type == RelationType.ANNOTATION) {
@@ -217,11 +211,11 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
 //                                 }
 //                    }
                 }
-                EventType.REDACTION                 -> {
+                EventType.REDACTION -> {
                     val eventToPrune = event.redacts?.let { EventEntity.where(realm, eventId = it).findFirst() }
                             ?: return
                     when (eventToPrune.type) {
-                        EventType.MESSAGE  -> {
+                        EventType.MESSAGE -> {
                             Timber.d("REDACTION for message ${eventToPrune.eventId}")
 //                                val unsignedData = EventMapper.map(eventToPrune).unsignedData
 //                                        ?: UnsignedData(null, null)
@@ -237,7 +231,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
                         }
                     }
                 }
-                in EventType.POLL_START             -> {
+                in EventType.POLL_START -> {
                     val content: MessagePollContent? = event.content.toModel()
                     if (content?.relatesTo?.type == RelationType.REPLACE) {
                         Timber.v("###REPLACE in room $roomId for event ${event.eventId}")
@@ -245,14 +239,18 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
                         handleReplace(realm, event, content, roomId, isLocalEcho)
                     }
                 }
-                in EventType.POLL_RESPONSE          -> {
+                in EventType.POLL_RESPONSE -> {
                     event.content.toModel<MessagePollResponseContent>(catchError = true)?.let {
-                        handleResponse(realm, event, it, roomId, isLocalEcho)
+                        sessionManager.getSessionComponent(sessionId)?.session()?.let { session ->
+                            pollAggregationProcessor.handlePollResponseEvent(session, realm, event)
+                        }
                     }
                 }
-                in EventType.POLL_END               -> {
-                    event.content.toModel<MessageEndPollContent>(catchError = true)?.let {
-                        handleEndPoll(realm, event, it, roomId, isLocalEcho)
+                in EventType.POLL_END -> {
+                    sessionManager.getSessionComponent(sessionId)?.session()?.let { session ->
+                        getPowerLevelsHelper(event.roomId)?.let {
+                            pollAggregationProcessor.handlePollEndEvent(session, it, realm, event)
+                        }
                     }
                 }
                 in EventType.STATE_ROOM_BEACON_INFO -> {
@@ -260,7 +258,10 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
                         liveLocationAggregationProcessor.handleBeaconInfo(realm, event, it, roomId, isLocalEcho)
                     }
                 }
-                else                                -> Timber.v("UnHandled event ${event.eventId}")
+                in EventType.BEACON_LOCATION_DATA -> {
+                    handleBeaconLocationData(event, realm, roomId, isLocalEcho)
+                }
+                else -> Timber.v("UnHandled event ${event.eventId}")
             }
         } catch (t: Throwable) {
             Timber.e(t, "## Should not happen ")
@@ -270,12 +271,14 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
     // OPT OUT serer aggregation until API mature enough
     private val SHOULD_HANDLE_SERVER_AGREGGATION = false // should be true to work with e2e
 
-    private fun handleReplace(realm: Realm,
-                              event: Event,
-                              content: MessageContent,
-                              roomId: String,
-                              isLocalEcho: Boolean,
-                              relatedEventId: String? = null) {
+    private fun handleReplace(
+            realm: Realm,
+            event: Event,
+            content: MessageContent,
+            roomId: String,
+            isLocalEcho: Boolean,
+            relatedEventId: String? = null
+    ) {
         val eventId = event.eventId ?: return
         val targetEventId = relatedEventId ?: content.relatesTo?.eventId ?: return
         val newContent = content.newContent ?: return
@@ -317,22 +320,6 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
                 return
             }
 
-            ContentMapper
-                    .map(eventAnnotationsSummaryEntity.pollResponseSummary?.aggregatedContent)
-                    ?.toModel<PollSummaryContent>()
-                    ?.let { existingPollSummaryContent ->
-                        eventAnnotationsSummaryEntity.pollResponseSummary?.aggregatedContent = ContentMapper.map(
-                                PollSummaryContent(
-                                        myVote = existingPollSummaryContent.myVote,
-                                        votes = emptyList(),
-                                        votesSummary = emptyMap(),
-                                        totalVotes = 0,
-                                        winnerVoteCount = 0,
-                                )
-                                        .toContent()
-                        )
-                    }
-
             val txId = event.unsignedData?.transactionId
             // is it a remote echo?
             if (!isLocalEcho && existingSummary.editions.any { it.eventId == txId }) {
@@ -362,6 +349,10 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
             }
         }
 
+        if (event.getClearType() in EventType.POLL_START) {
+            pollAggregationProcessor.handlePollStartEvent(realm, event)
+        }
+
         if (!isLocalEcho) {
             val replaceEvent = TimelineEventEntity
                     .where(realm, roomId, eventId)
@@ -375,10 +366,13 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
      * 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
+     * @param editions list of edition of event
      */
-    private fun handleThreadSummaryEdition(editedEvent: EventEntity?,
-                                           replaceEvent: TimelineEventEntity?,
-                                           editions: List<EditionOfEvent>?) {
+    private fun handleThreadSummaryEdition(
+            editedEvent: EventEntity?,
+            replaceEvent: TimelineEventEntity?,
+            editions: List<EditionOfEvent>?
+    ) {
         replaceEvent ?: return
         editedEvent ?: return
         editedEvent.findRootThreadEvent()?.apply {
@@ -391,179 +385,18 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
         }
     }
 
-    private fun handleResponse(realm: Realm,
-                               event: Event,
-                               content: MessagePollResponseContent,
-                               roomId: String,
-                               isLocalEcho: Boolean,
-                               relatedEventId: String? = null) {
-        val eventId = event.eventId ?: return
-        val senderId = event.senderId ?: return
-        val targetEventId = relatedEventId ?: content.relatesTo?.eventId ?: return
-        val eventTimestamp = event.originServerTs ?: return
-
-        val targetPollContent = getPollContent(roomId, targetEventId) ?: return
-
-        // ok, this is a poll response
-        var existing = EventAnnotationsSummaryEntity.where(realm, roomId, targetEventId).findFirst()
-        if (existing == null) {
-            Timber.v("## POLL creating new relation summary for $targetEventId")
-            existing = EventAnnotationsSummaryEntity.create(realm, roomId, targetEventId)
-        }
-
-        // we have it
-        val existingPollSummary = existing.pollResponseSummary
-                ?: realm.createObject(PollResponseAggregatedSummaryEntity::class.java).also {
-                    existing.pollResponseSummary = it
-                }
-
-        val closedTime = existingPollSummary.closedTime
-        if (closedTime != null && eventTimestamp > closedTime) {
-            Timber.v("## POLL is closed ignore event poll:$targetEventId, event :${event.eventId}")
-            return
-        }
-
-        val currentModel = ContentMapper.map(existingPollSummary.aggregatedContent).toModel<PollSummaryContent>()
-
-        if (existingPollSummary.sourceEvents.contains(eventId)) {
-            // ignore this event, we already know it (??)
-            Timber.v("## POLL  ignoring event for summary, it's known eventId:$eventId")
-            return
-        }
-        val txId = event.unsignedData?.transactionId
-        // is it a remote echo?
-        if (!isLocalEcho && existingPollSummary.sourceLocalEchoEvents.contains(txId)) {
-            // ok it has already been managed
-            Timber.v("## POLL  Receiving remote echo of response eventId:$eventId")
-            existingPollSummary.sourceLocalEchoEvents.remove(txId)
-            existingPollSummary.sourceEvents.add(event.eventId)
-            return
-        }
-
-        val option = content.getBestResponse()?.answers?.first() ?: return Unit.also {
-            Timber.d("## POLL Ignoring malformed response no option eventId:$eventId content: ${event.content}")
-        }
-
-        // Check if this option is in available options
-        if (!targetPollContent.getBestPollCreationInfo()?.answers?.map { it.id }?.contains(option).orFalse()) {
-            Timber.v("## POLL $targetEventId doesn't contain option $option")
-            return
-        }
-
-        val votes = currentModel?.votes.orEmpty().toMutableList()
-
-        var myVote: String? = null
-        val existingVoteIndex = votes.indexOfFirst { it.userId == senderId }
-        if (existingVoteIndex != -1) {
-            // Is the vote newer?
-            val existingVote = votes[existingVoteIndex]
-            if (existingVote.voteTimestamp < eventTimestamp) {
-                // Take the new one
-                votes[existingVoteIndex] = VoteInfo(senderId, option, eventTimestamp)
-                if (userId == senderId) {
-                    myVote = option
-                }
-                Timber.v("## POLL adding vote $option for user $senderId in poll :$targetEventId ")
-            } else {
-                Timber.v("## POLL Ignoring vote (older than known one)  eventId:$eventId ")
-            }
-        } else {
-            votes.add(VoteInfo(senderId, option, eventTimestamp))
-            if (userId == senderId) {
-                myVote = option
-            }
-            Timber.v("## POLL adding vote $option for user $senderId in poll :$targetEventId ")
-        }
-
-        // Precompute the percentage of votes for all options
-        val totalVotes = votes.size
-        val newVotesSummary = votes
-                .groupBy({ it.option }, { it.userId })
-                .mapValues {
-                    VoteSummary(
-                            total = it.value.size,
-                            percentage = if (totalVotes == 0 && it.value.isEmpty()) 0.0 else it.value.size.toDouble() / totalVotes
-                    )
-                }
-        val newWinnerVoteCount = newVotesSummary.maxOf { it.value.total }
-
-        if (isLocalEcho) {
-            existingPollSummary.sourceLocalEchoEvents.add(eventId)
-        } else {
-            existingPollSummary.sourceEvents.add(eventId)
-        }
-
-        val newSumModel = PollSummaryContent(
-                myVote = myVote,
-                votes = votes,
-                votesSummary = newVotesSummary,
-                totalVotes = totalVotes,
-                winnerVoteCount = newWinnerVoteCount
-        )
-
-        existingPollSummary.aggregatedContent = ContentMapper.map(newSumModel.toContent())
-    }
-
-    private fun handleEndPoll(realm: Realm,
-                              event: Event,
-                              content: MessageEndPollContent,
-                              roomId: String,
-                              isLocalEcho: Boolean) {
-        val pollEventId = content.relatesTo?.eventId ?: return
-        val pollOwnerId = getPollEvent(roomId, pollEventId)?.root?.senderId
-        val isPollOwner = pollOwnerId == event.senderId
-        val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
+    private fun getPowerLevelsHelper(roomId: String): PowerLevelsHelper? {
+        return stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
                 ?.content?.toModel<PowerLevelsContent>()
                 ?.let { PowerLevelsHelper(it) }
-
-        if (!isPollOwner && !powerLevelsHelper?.isUserAbleToRedact(event.senderId ?: "").orFalse()) {
-            Timber.v("## Received poll.end event $pollEventId but user ${event.senderId} doesn't have enough power level in room $roomId")
-            return
-        }
-
-        var existingPoll = EventAnnotationsSummaryEntity.where(realm, roomId, pollEventId).findFirst()
-        if (existingPoll == null) {
-            Timber.v("## POLL creating new relation summary for $pollEventId")
-            existingPoll = EventAnnotationsSummaryEntity.create(realm, roomId, pollEventId)
-        }
-
-        // we have it
-        val existingPollSummary = existingPoll.pollResponseSummary
-                ?: realm.createObject(PollResponseAggregatedSummaryEntity::class.java).also {
-                    existingPoll.pollResponseSummary = it
-                }
-
-        val txId = event.unsignedData?.transactionId
-        existingPollSummary.closedTime = event.originServerTs
-
-        // is it a remote echo?
-        if (!isLocalEcho && existingPollSummary.sourceLocalEchoEvents.contains(txId)) {
-            // ok it has already been managed
-            Timber.v("## POLL  Receiving remote echo of response eventId:$pollEventId")
-            existingPollSummary.sourceLocalEchoEvents.remove(txId)
-            existingPollSummary.sourceEvents.add(event.eventId)
-        }
     }
 
-    private fun getPollEvent(roomId: String, eventId: String): TimelineEvent? {
-        val session = sessionManager.getSessionComponent(sessionId)?.session()
-        return session?.roomService()?.getRoom(roomId)?.getTimelineEvent(eventId) ?: return null.also {
-            Timber.v("## POLL target poll event $eventId not found in room $roomId")
-        }
-    }
-
-    private fun getPollContent(roomId: String, eventId: String): MessagePollContent? {
-        val pollEvent = getPollEvent(roomId, eventId) ?: return null
-
-        return pollEvent.getLastMessageContent() as? MessagePollContent ?: return null.also {
-            Timber.v("## POLL target poll event $eventId content is malformed")
-        }
-    }
-
-    private fun handleInitialAggregatedRelations(realm: Realm,
-                                                 event: Event,
-                                                 roomId: String,
-                                                 aggregation: AggregatedAnnotation) {
+    private fun handleInitialAggregatedRelations(
+            realm: Realm,
+            event: Event,
+            roomId: String,
+            aggregation: AggregatedAnnotation
+    ) {
         if (SHOULD_HANDLE_SERVER_AGREGGATION) {
             aggregation.chunk?.forEach {
                 if (it.type == EventType.REACTION) {
@@ -585,10 +418,12 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
         }
     }
 
-    private fun handleReaction(realm: Realm,
-                               event: Event,
-                               roomId: String,
-                               isLocalEcho: Boolean) {
+    private fun handleReaction(
+            realm: Realm,
+            event: Event,
+            roomId: String,
+            isLocalEcho: Boolean
+    ) {
         val content = event.content.toModel<ReactionContent>()
         if (content == null) {
             Timber.e("Malformed reaction content ${event.content}")
@@ -653,9 +488,11 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
     /**
      * Called when an event is deleted.
      */
-    private fun handleRedactionOfReplace(realm: Realm,
-                                         redacted: EventEntity,
-                                         relatedEventId: String) {
+    private fun handleRedactionOfReplace(
+            realm: Realm,
+            redacted: EventEntity,
+            relatedEventId: String
+    ) {
         Timber.d("Handle redaction of m.replace")
         val eventSummary = EventAnnotationsSummaryEntity.where(realm, redacted.roomId, relatedEventId).findFirst()
         if (eventSummary == null) {
@@ -671,8 +508,10 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
         sourceToDiscard.deleteFromRealm()
     }
 
-    private fun handleReactionRedact(realm: Realm,
-                                     eventToPrune: EventEntity) {
+    private fun handleReactionRedact(
+            realm: Realm,
+            eventToPrune: EventEntity
+    ) {
         Timber.v("REDACTION of reaction ${eventToPrune.eventId}")
         // delete a reaction, need to update the annotation summary if any
         val reactionContent: ReactionContent = EventMapper.map(eventToPrune).content.toModel() ?: return
@@ -733,7 +572,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
                 EventType.KEY_VERIFICATION_ACCEPT,
                 EventType.KEY_VERIFICATION_READY,
                 EventType.KEY_VERIFICATION_KEY,
-                EventType.KEY_VERIFICATION_MAC    -> currentState.toState(VerificationState.WAITING)
+                EventType.KEY_VERIFICATION_MAC -> currentState.toState(VerificationState.WAITING)
                 EventType.KEY_VERIFICATION_CANCEL -> currentState.toState(
                         if (event.senderId == userId) {
                             VerificationState.CANCELED_BY_ME
@@ -741,8 +580,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
                             VerificationState.CANCELED_BY_OTHER
                         }
                 )
-                EventType.KEY_VERIFICATION_DONE   -> currentState.toState(VerificationState.DONE)
-                else                              -> VerificationState.REQUEST
+                EventType.KEY_VERIFICATION_DONE -> currentState.toState(VerificationState.DONE)
+                else -> VerificationState.REQUEST
             }
 
             data = data.copy(verificationState = newState)
@@ -756,4 +595,17 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
             verifSummary.sourceEvents.add(event.eventId)
         }
     }
+
+    private fun handleBeaconLocationData(event: Event, realm: Realm, roomId: String, isLocalEcho: Boolean) {
+        event.getClearContent().toModel<MessageBeaconLocationDataContent>(catchError = true)?.let {
+            liveLocationAggregationProcessor.handleBeaconLocationData(
+                    realm,
+                    event,
+                    it,
+                    roomId,
+                    event.getRelationContent()?.eventId,
+                    isLocalEcho
+            )
+        }
+    }
 }
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 72f56ddf688524128ec8a77b13b04daa8315f1b4..ac2880de69946da33fc1ddb58db47ce03a2d33f2 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
@@ -58,8 +58,9 @@ internal interface RoomAPI {
      * Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-publicrooms
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "publicRooms")
-    suspend fun publicRooms(@Query("server") server: String?,
-                            @Body publicRoomsParams: PublicRoomsParams
+    suspend fun publicRooms(
+            @Query("server") server: String?,
+            @Body publicRoomsParams: PublicRoomsParams
     ): PublicRoomsResponse
 
     /**
@@ -78,138 +79,156 @@ internal interface RoomAPI {
      * Get a list of messages starting from a reference.
      *
      * @param roomId the room id
-     * @param from   the token identifying where to start. Required.
-     * @param dir    The direction to return messages from. Required.
-     * @param limit  the maximum number of messages to retrieve. Optional.
+     * @param from the token identifying where to start. Required.
+     * @param dir The direction to return messages from. Required.
+     * @param limit the maximum number of messages to retrieve. Optional.
      * @param filter A JSON RoomEventFilter to filter returned events with. Optional.
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/messages")
-    suspend fun getRoomMessagesFrom(@Path("roomId") roomId: String,
-                                    @Query("from") from: String,
-                                    @Query("dir") dir: String,
-                                    @Query("limit") limit: Int?,
-                                    @Query("filter") filter: String?
+    suspend fun getRoomMessagesFrom(
+            @Path("roomId") roomId: String,
+            @Query("from") from: String,
+            @Query("dir") dir: String,
+            @Query("limit") limit: Int?,
+            @Query("filter") filter: String?
     ): PaginationResponse
 
     /**
      * Get all members of a room.
      *
-     * @param roomId        the room id where to get the members
-     * @param syncToken     the sync token (optional)
-     * @param membership    to include only one type of membership (optional)
+     * @param roomId the room id where to get the members
+     * @param syncToken the sync token (optional)
+     * @param membership to include only one type of membership (optional)
      * @param notMembership to exclude one type of membership (optional)
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/members")
-    suspend fun getMembers(@Path("roomId") roomId: String,
-                           @Query("at") syncToken: String?,
-                           @Query("membership") membership: Membership?,
-                           @Query("not_membership") notMembership: Membership?
+    suspend fun getMembers(
+            @Path("roomId") roomId: String,
+            @Query("at") syncToken: String?,
+            @Query("membership") membership: Membership?,
+            @Query("not_membership") notMembership: Membership?
     ): RoomMembersResponse
 
     /**
      * Send an event to a room.
      *
-     * @param txId      the transaction Id
-     * @param roomId    the room id
+     * @param txId the transaction Id
+     * @param roomId the room id
      * @param eventType the event type
-     * @param content   the event content
+     * @param content the event content
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/send/{eventType}/{txId}")
-    suspend fun send(@Path("txId") txId: String,
-                     @Path("roomId") roomId: String,
-                     @Path("eventType") eventType: String,
-                     @Body content: Content?
+    suspend fun send(
+            @Path("txId") txId: String,
+            @Path("roomId") roomId: String,
+            @Path("eventType") eventType: String,
+            @Body content: Content?
     ): SendResponse
 
     /**
      * Get the context surrounding an event.
      *
-     * @param roomId  the room id
+     * @param roomId the room id
      * @param eventId the event Id
-     * @param limit   the maximum number of messages to retrieve
-     * @param filter  A JSON RoomEventFilter to filter returned events with. Optional.
+     * @param limit the maximum number of messages to retrieve
+     * @param filter A JSON RoomEventFilter to filter returned events with. Optional.
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/context/{eventId}")
-    suspend fun getContextOfEvent(@Path("roomId") roomId: String,
-                                  @Path("eventId") eventId: String,
-                                  @Query("limit") limit: Int,
-                                  @Query("filter") filter: String? = null): EventContextResponse
+    suspend fun getContextOfEvent(
+            @Path("roomId") roomId: String,
+            @Path("eventId") eventId: String,
+            @Query("limit") limit: Int,
+            @Query("filter") filter: String? = null
+    ): EventContextResponse
 
     /**
      * Retrieve an event from its room id / events id.
      *
-     * @param roomId  the room id
+     * @param roomId the room id
      * @param eventId the event Id
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/event/{eventId}")
-    suspend fun getEvent(@Path("roomId") roomId: String,
-                         @Path("eventId") eventId: String): Event
+    suspend fun getEvent(
+            @Path("roomId") roomId: String,
+            @Path("eventId") eventId: String
+    ): Event
 
     /**
      * Send read markers.
      *
-     * @param roomId  the room id
+     * @param roomId the room id
      * @param markers the read markers
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/read_markers")
-    suspend fun sendReadMarker(@Path("roomId") roomId: String,
-                               @Body markers: Map<String, String>)
+    suspend fun sendReadMarker(
+            @Path("roomId") roomId: String,
+            @Body markers: Map<String, String>
+    )
 
     /**
      * Send receipt to a room.
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/receipt/{receiptType}/{eventId}")
-    suspend fun sendReceipt(@Path("roomId") roomId: String,
-                            @Path("receiptType") receiptType: String,
-                            @Path("eventId") eventId: String,
-                            @Body body: JsonDict = emptyMap())
+    suspend fun sendReceipt(
+            @Path("roomId") roomId: String,
+            @Path("receiptType") receiptType: String,
+            @Path("eventId") eventId: String,
+            @Body body: JsonDict = emptyMap()
+    )
 
     /**
      * Invite a user to the given room.
      * Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-rooms-roomid-invite
      *
      * @param roomId the room id
-     * @param body   a object that just contains a user id
+     * @param body a object that just contains a user id
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/invite")
-    suspend fun invite(@Path("roomId") roomId: String,
-                       @Body body: InviteBody)
+    suspend fun invite(
+            @Path("roomId") roomId: String,
+            @Body body: InviteBody
+    )
 
     /**
      * Invite a user to a room, using a ThreePid
      * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#id101
      * @param roomId Required. The room identifier (not alias) to which to invite the user.
+     * @param body the Json body
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/invite")
-    suspend fun invite3pid(@Path("roomId") roomId: String,
-                           @Body body: ThreePidInviteBody)
+    suspend fun invite3pid(
+            @Path("roomId") roomId: String,
+            @Body body: ThreePidInviteBody
+    )
 
     /**
      * Send a generic state event.
      *
-     * @param roomId         the room id.
+     * @param roomId the room id.
      * @param stateEventType the state event type
-     * @param params         the request parameters
+     * @param params the request parameters
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/state/{state_event_type}")
-    suspend fun sendStateEvent(@Path("roomId") roomId: String,
-                               @Path("state_event_type") stateEventType: String,
-                               @Body params: JsonDict
+    suspend fun sendStateEvent(
+            @Path("roomId") roomId: String,
+            @Path("state_event_type") stateEventType: String,
+            @Body params: JsonDict
     ): SendResponse
 
     /**
      * Send a generic state event.
      *
-     * @param roomId         the room id.
+     * @param roomId the room id.
      * @param stateEventType the state event type
-     * @param stateKey       the state keys
-     * @param params         the request parameters
+     * @param stateKey the state keys
+     * @param params the request parameters
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/state/{state_event_type}/{state_key}")
-    suspend fun sendStateEvent(@Path("roomId") roomId: String,
-                               @Path("state_event_type") stateEventType: String,
-                               @Path("state_key") stateKey: String,
-                               @Body params: JsonDict
+    suspend fun sendStateEvent(
+            @Path("roomId") roomId: String,
+            @Path("state_event_type") stateEventType: String,
+            @Path("state_key") stateKey: String,
+            @Body params: JsonDict
     ): SendResponse
 
     /**
@@ -221,30 +240,43 @@ internal interface RoomAPI {
 
     /**
      * Paginate relations for event based in normal topological order.
+     * @param roomId the room Id
+     * @param eventId the event Id
      * @param relationType filter for this relation type
      * @param eventType filter for this event type
+     * @param from from token
+     * @param to to token
+     * @param limit max number of Event to retrieve
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "rooms/{roomId}/relations/{eventId}/{relationType}/{eventType}")
-    suspend fun getRelations(@Path("roomId") roomId: String,
-                             @Path("eventId") eventId: String,
-                             @Path("relationType") relationType: String,
-                             @Path("eventType") eventType: String,
-                             @Query("from") from: String? = null,
-                             @Query("to") to: String? = null,
-                             @Query("limit") limit: Int? = null
+    suspend fun getRelations(
+            @Path("roomId") roomId: String,
+            @Path("eventId") eventId: String,
+            @Path("relationType") relationType: String,
+            @Path("eventType") eventType: String,
+            @Query("from") from: String? = null,
+            @Query("to") to: String? = null,
+            @Query("limit") limit: Int? = null
     ): RelationsResponse
 
     /**
      * Paginate relations for thread events based in normal topological order.
+     *
+     * @param roomId the room Id
+     * @param eventId the event Id
      * @param relationType filter for this relation type
+     * @param from from token
+     * @param to to token
+     * @param limit max number of Event to retrieve
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "rooms/{roomId}/relations/{eventId}/{relationType}")
-    suspend fun getThreadsRelations(@Path("roomId") roomId: String,
-                                    @Path("eventId") eventId: String,
-                                    @Path("relationType") relationType: String = RelationType.THREAD,
-                                    @Query("from") from: String? = null,
-                                    @Query("to") to: String? = null,
-                                    @Query("limit") limit: Int? = null
+    suspend fun getThreadsRelations(
+            @Path("roomId") roomId: String,
+            @Path("eventId") eventId: String,
+            @Path("relationType") relationType: String = RelationType.THREAD,
+            @Query("from") from: String? = null,
+            @Query("to") to: String? = null,
+            @Query("limit") limit: Int? = null
     ): RelationsResponse
 
     /**
@@ -255,59 +287,69 @@ internal interface RoomAPI {
      * @param params the request body
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "join/{roomIdOrAlias}")
-    suspend fun join(@Path("roomIdOrAlias") roomIdOrAlias: String,
-                     @Query("server_name") viaServers: List<String>,
-                     @Body params: JsonDict): JoinRoomResponse
+    suspend fun join(
+            @Path("roomIdOrAlias") roomIdOrAlias: String,
+            @Query("server_name") viaServers: List<String>,
+            @Body params: JsonDict
+    ): JoinRoomResponse
 
     /**
      * Leave the given room.
      *
-     * @param roomId  the room id
+     * @param roomId the room id
      * @param params the request body
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/leave")
-    suspend fun leave(@Path("roomId") roomId: String,
-                      @Body params: Map<String, String?>)
+    suspend fun leave(
+            @Path("roomId") roomId: String,
+            @Body params: Map<String, String?>
+    )
 
     /**
      * Ban a user from the given room.
      *
-     * @param roomId          the room id
+     * @param roomId the room id
      * @param userIdAndReason the banned user object (userId and reason for ban)
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/ban")
-    suspend fun ban(@Path("roomId") roomId: String,
-                    @Body userIdAndReason: UserIdAndReason)
+    suspend fun ban(
+            @Path("roomId") roomId: String,
+            @Body userIdAndReason: UserIdAndReason
+    )
 
     /**
      * unban a user from the given room.
      *
-     * @param roomId          the room id
+     * @param roomId the room id
      * @param userIdAndReason the unbanned user object (userId and reason for unban)
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/unban")
-    suspend fun unban(@Path("roomId") roomId: String,
-                      @Body userIdAndReason: UserIdAndReason)
+    suspend fun unban(
+            @Path("roomId") roomId: String,
+            @Body userIdAndReason: UserIdAndReason
+    )
 
     /**
      * Kick a user from the given room.
      *
-     * @param roomId          the room id
+     * @param roomId the room id
      * @param userIdAndReason the kicked user object (userId and reason for kicking)
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/kick")
-    suspend fun kick(@Path("roomId") roomId: String,
-                     @Body userIdAndReason: UserIdAndReason)
+    suspend fun kick(
+            @Path("roomId") roomId: String,
+            @Body userIdAndReason: UserIdAndReason
+    )
 
     /**
      * Strips all information out of an event which isn't critical to the integrity of the server-side representation of the room.
      * This cannot be undone.
      * Users may redact their own events, and any user with a power level greater than or equal to the redact power level of the room may redact events there.
      *
-     * @param txId     the transaction Id
-     * @param roomId   the room id
-     * @param eventId  the event to delete
-     * @param reason   json containing reason key {"reason": "Indecent material"}
+     * @param txId the transaction Id
+     * @param roomId the room id
+     * @param eventId the event to delete
+     * @param reason json containing reason key {"reason": "Indecent material"}
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/redact/{eventId}/{txnId}")
     suspend fun redactEvent(
@@ -320,14 +362,16 @@ internal interface RoomAPI {
     /**
      * Reports an event as inappropriate to the server, which may then notify the appropriate people.
      *
-     * @param roomId  the room id
+     * @param roomId the room id
      * @param eventId the event to report content
-     * @param body    body containing score and reason
+     * @param body body containing score and reason
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/report/{eventId}")
-    suspend fun reportContent(@Path("roomId") roomId: String,
-                              @Path("eventId") eventId: String,
-                              @Body body: ReportContentBody)
+    suspend fun reportContent(
+            @Path("roomId") roomId: String,
+            @Path("eventId") eventId: String,
+            @Body body: ReportContentBody
+    )
 
     /**
      * Get a list of aliases maintained by the local server for the given room.
@@ -340,9 +384,11 @@ internal interface RoomAPI {
      * 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)
+    suspend fun sendTypingState(
+            @Path("roomId") roomId: String,
+            @Path("userId") userId: String,
+            @Body body: TypingBody
+    )
 
     /*
      * Room tagging
@@ -352,27 +398,33 @@ internal interface RoomAPI {
      * Add a tag to a room.
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/rooms/{roomId}/tags/{tag}")
-    suspend fun putTag(@Path("userId") userId: String,
-                       @Path("roomId") roomId: String,
-                       @Path("tag") tag: String,
-                       @Body body: TagBody)
+    suspend fun putTag(
+            @Path("userId") userId: String,
+            @Path("roomId") roomId: String,
+            @Path("tag") tag: String,
+            @Body body: TagBody
+    )
 
     /**
      * Delete a tag from a room.
      */
     @DELETE(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/rooms/{roomId}/tags/{tag}")
-    suspend fun deleteTag(@Path("userId") userId: String,
-                          @Path("roomId") roomId: String,
-                          @Path("tag") tag: String)
+    suspend fun deleteTag(
+            @Path("userId") userId: String,
+            @Path("roomId") roomId: String,
+            @Path("tag") tag: String
+    )
 
     /**
      * Set an AccountData event to the room.
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/rooms/{roomId}/account_data/{type}")
-    suspend fun setRoomAccountData(@Path("userId") userId: String,
-                                   @Path("roomId") roomId: String,
-                                   @Path("type") type: String,
-                                   @Body content: JsonDict)
+    suspend fun setRoomAccountData(
+            @Path("userId") userId: String,
+            @Path("roomId") roomId: String,
+            @Path("type") type: String,
+            @Body content: JsonDict
+    )
 
     /**
      * Upgrades the given room to a particular room version.
@@ -382,8 +434,10 @@ internal interface RoomAPI {
      * 403: The user is not permitted to upgrade the room.(M_FORBIDDEN)
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/upgrade")
-    suspend fun upgradeRoom(@Path("roomId") roomId: String,
-                            @Body body: RoomUpgradeBody): RoomUpgradeResponse
+    suspend fun upgradeRoom(
+            @Path("roomId") roomId: String,
+            @Body body: RoomUpgradeBody
+    ): RoomUpgradeResponse
 
     /**
      * The API returns the summary of the specified room, if the room could be found and the client should be able to view
@@ -392,6 +446,8 @@ internal interface RoomAPI {
      * https://github.com/deepbluev7/matrix-doc/blob/room-summaries/proposals/3266-room-summary.md
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "im.nheko.summary/rooms/{roomIdOrAlias}/summary")
-    suspend fun getRoomSummary(@Path("roomIdOrAlias") roomidOrAlias: String,
-                               @Query("via") viaServers: List<String>?): RoomStrippedState
+    suspend fun getRoomSummary(
+            @Path("roomIdOrAlias") roomidOrAlias: String,
+            @Query("via") viaServers: List<String>?
+    ): RoomStrippedState
 }
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 29a303475bc17898db0d108dad2498e0de0af3dd..c3d55b267ab812106b008b382fa82e0428c0cde9 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
@@ -35,7 +35,7 @@ internal class RoomAvatarResolver @Inject constructor(@UserId private val userId
 
     /**
      * Compute the room avatar url.
-     * @param realm: the current instance of realm
+     * @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/RoomFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt
index 01c4fd1501dba0eb9895409b8d7a8e36f509e7f6..ffe7679575f2a89a5efaac3286469973a0d1459e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt
@@ -25,6 +25,7 @@ import org.matrix.android.sdk.internal.session.room.alias.DefaultAliasService
 import org.matrix.android.sdk.internal.session.room.call.DefaultRoomCallService
 import org.matrix.android.sdk.internal.session.room.crypto.DefaultRoomCryptoService
 import org.matrix.android.sdk.internal.session.room.draft.DefaultDraftService
+import org.matrix.android.sdk.internal.session.room.location.DefaultLocationSharingService
 import org.matrix.android.sdk.internal.session.room.membership.DefaultMembershipService
 import org.matrix.android.sdk.internal.session.room.notification.DefaultRoomPushRuleService
 import org.matrix.android.sdk.internal.session.room.read.DefaultReadService
@@ -69,6 +70,7 @@ internal class DefaultRoomFactory @Inject constructor(
         private val roomVersionServiceFactory: DefaultRoomVersionService.Factory,
         private val roomAccountDataServiceFactory: DefaultRoomAccountDataService.Factory,
         private val viaParameterFinder: ViaParameterFinder,
+        private val locationSharingServiceFactory: DefaultLocationSharingService.Factory,
         private val coroutineDispatchers: MatrixCoroutineDispatchers
 ) : RoomFactory {
 
@@ -96,6 +98,7 @@ internal class DefaultRoomFactory @Inject constructor(
                 roomAccountDataService = roomAccountDataServiceFactory.create(roomId),
                 roomVersionService = roomVersionServiceFactory.create(roomId),
                 viaParameterFinder = viaParameterFinder,
+                locationSharingService = locationSharingServiceFactory.create(roomId),
                 coroutineDispatchers = coroutineDispatchers
         )
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/DefaultRoomAccountDataService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/DefaultRoomAccountDataService.kt
index caeeb3bf5375aeea24618a76028edbe7a61a1d23..aea786b46b4783031f2b7853d877a0f8b8fbad5a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/DefaultRoomAccountDataService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/DefaultRoomAccountDataService.kt
@@ -25,9 +25,10 @@ import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent
 import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataService
 import org.matrix.android.sdk.api.util.Optional
 
-internal class DefaultRoomAccountDataService @AssistedInject constructor(@Assisted private val roomId: String,
-                                                                         private val dataSource: RoomAccountDataDataSource,
-                                                                         private val updateRoomAccountDataTask: UpdateRoomAccountDataTask
+internal class DefaultRoomAccountDataService @AssistedInject constructor(
+        @Assisted private val roomId: String,
+        private val dataSource: RoomAccountDataDataSource,
+        private val updateRoomAccountDataTask: UpdateRoomAccountDataTask
 ) : RoomAccountDataService {
 
     @AssistedFactory
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt
index d5a110dfc28993c21e16bb6deb95e5523d6254fb..5196f004ea5431a8a42182fbe080e3c76aedce39 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt
@@ -33,9 +33,11 @@ import org.matrix.android.sdk.internal.database.model.RoomEntityFields
 import org.matrix.android.sdk.internal.di.SessionDatabase
 import javax.inject.Inject
 
-internal class RoomAccountDataDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
-                                                             private val realmSessionProvider: RealmSessionProvider,
-                                                             private val accountDataMapper: AccountDataMapper) {
+internal class RoomAccountDataDataSource @Inject constructor(
+        @SessionDatabase private val monarchy: Monarchy,
+        private val realmSessionProvider: RealmSessionProvider,
+        private val accountDataMapper: AccountDataMapper
+) {
 
     fun getAccountDataEvent(roomId: String, type: String): RoomAccountDataEvent? {
         return getAccountDataEvents(roomId, setOf(type)).firstOrNull()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DeactivateLiveLocationShareWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DeactivateLiveLocationShareWorker.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b17753b25a37fdc1d5d7d10cd7a062d097255594
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DeactivateLiveLocationShareWorker.kt
@@ -0,0 +1,98 @@
+/*
+ * 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.aggregation.livelocation
+
+import android.content.Context
+import androidx.work.WorkerParameters
+import com.squareup.moshi.JsonClass
+import io.realm.RealmConfiguration
+import org.matrix.android.sdk.api.util.md5
+import org.matrix.android.sdk.internal.SessionManager
+import org.matrix.android.sdk.internal.database.awaitTransaction
+import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
+import org.matrix.android.sdk.internal.database.query.get
+import org.matrix.android.sdk.internal.di.SessionDatabase
+import org.matrix.android.sdk.internal.session.SessionComponent
+import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
+import org.matrix.android.sdk.internal.worker.SessionWorkerParams
+import timber.log.Timber
+import javax.inject.Inject
+
+/**
+ * Worker dedicated to update live location summary data so that it is considered as deactivated.
+ * For the context: it is needed since a live location share should be deactivated after a certain timeout.
+ */
+internal class DeactivateLiveLocationShareWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
+        SessionSafeCoroutineWorker<DeactivateLiveLocationShareWorker.Params>(
+                context,
+                params,
+                sessionManager,
+                Params::class.java
+        ) {
+
+    @JsonClass(generateAdapter = true)
+    internal data class Params(
+            override val sessionId: String,
+            override val lastFailureMessage: String? = null,
+            val eventId: String,
+            val roomId: String
+    ) : SessionWorkerParams
+
+    @SessionDatabase
+    @Inject lateinit var realmConfiguration: RealmConfiguration
+
+    override fun injectWith(injector: SessionComponent) {
+        injector.inject(this)
+    }
+
+    override suspend fun doSafeWork(params: Params): Result {
+        return runCatching {
+            deactivateLiveLocationShare(params)
+        }.fold(
+                onSuccess = {
+                    Result.success()
+                },
+                onFailure = {
+                    Timber.e("failed to deactivate live, eventId: ${params.eventId}, roomId: ${params.roomId}")
+                    Result.failure()
+                }
+        )
+    }
+
+    private suspend fun deactivateLiveLocationShare(params: Params) {
+        awaitTransaction(realmConfiguration) { realm ->
+            Timber.d("deactivating live with id=${params.eventId}")
+            val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.get(
+                    realm = realm,
+                    roomId = params.roomId,
+                    eventId = params.eventId
+            )
+            aggregatedSummary?.isActive = false
+        }
+    }
+
+    override fun buildErrorParams(params: Params, message: String): Params {
+        return params.copy(lastFailureMessage = params.lastFailureMessage ?: message)
+    }
+
+    companion object {
+        fun getWorkName(eventId: String, roomId: String): String {
+            val hash = "$eventId$roomId".md5()
+            return "DeactivateLiveLocationWork-$hash"
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt
deleted file mode 100644
index 997e31a1091e51b62c75d8086225d60e0346d252..0000000000000000000000000000000000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.session.room.aggregation.livelocation
-
-import io.realm.Realm
-import org.matrix.android.sdk.api.extensions.orTrue
-import org.matrix.android.sdk.api.session.events.model.Event
-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.room.model.message.MessageBeaconInfoContent
-import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
-import org.matrix.android.sdk.internal.database.mapper.ContentMapper
-import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
-import org.matrix.android.sdk.internal.database.query.getOrCreate
-import timber.log.Timber
-import javax.inject.Inject
-
-internal class DefaultLiveLocationAggregationProcessor @Inject constructor() : LiveLocationAggregationProcessor {
-
-    override fun handleBeaconInfo(realm: Realm, event: Event, content: MessageBeaconInfoContent, roomId: String, isLocalEcho: Boolean) {
-        if (event.senderId.isNullOrEmpty() || isLocalEcho) {
-            return
-        }
-
-        val targetEventId = if (content.isLive.orTrue()) {
-            event.eventId
-        } else {
-            // when live is set to false, we use the id of the event that should have been replaced
-            event.unsignedData?.replacesState
-        }
-
-        if (targetEventId.isNullOrEmpty()) {
-            Timber.w("no target event id found for the beacon content")
-            return
-        }
-
-        val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate(
-                realm = realm,
-                roomId = roomId,
-                eventId = targetEventId
-        )
-
-        Timber.d("updating summary of id=$targetEventId with isLive=${content.isLive}")
-
-        aggregatedSummary.endOfLiveTimestampMillis = content.getBestTimestampMillis()?.let { it + (content.timeout ?: 0) }
-        aggregatedSummary.isActive = content.isLive
-    }
-
-    override fun handleBeaconLocationData(realm: Realm, event: Event, content: MessageBeaconLocationDataContent, roomId: String, isLocalEcho: Boolean) {
-        if (event.senderId.isNullOrEmpty() || isLocalEcho) {
-            return
-        }
-
-        val targetEventId = content.relatesTo?.eventId
-
-        if (targetEventId.isNullOrEmpty()) {
-            Timber.w("no target event id found for the live location content")
-            return
-        }
-
-        val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate(
-                realm = realm,
-                roomId = roomId,
-                eventId = targetEventId
-        )
-        val updatedLocationTimestamp = content.getBestTimestampMillis() ?: 0
-        val currentLocationTimestamp = ContentMapper
-                .map(aggregatedSummary.lastLocationContent)
-                .toModel<MessageBeaconLocationDataContent>()
-                ?.getBestTimestampMillis()
-                ?: 0
-
-        if (updatedLocationTimestamp.isMoreRecentThan(currentLocationTimestamp)) {
-            Timber.d("updating last location of the summary of id=$targetEventId")
-            aggregatedSummary.lastLocationContent = ContentMapper.map(content.toContent())
-        }
-    }
-
-    private fun Long.isMoreRecentThan(timestamp: Long) = this > timestamp
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt
index c0be96f83d6af59a3084055df0bc7b89f6bdccce..05bde8f83f9214beda1bb6d9ac86e83c4000791d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt
@@ -16,25 +16,145 @@
 
 package org.matrix.android.sdk.internal.session.room.aggregation.livelocation
 
+import androidx.work.ExistingWorkPolicy
 import io.realm.Realm
+import org.matrix.android.sdk.api.extensions.orTrue
 import org.matrix.android.sdk.api.session.events.model.Event
+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.room.model.message.MessageBeaconInfoContent
 import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
+import org.matrix.android.sdk.internal.database.mapper.ContentMapper
+import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
+import org.matrix.android.sdk.internal.database.query.findActiveLiveInRoomForUser
+import org.matrix.android.sdk.internal.database.query.getOrCreate
+import org.matrix.android.sdk.internal.di.SessionId
+import org.matrix.android.sdk.internal.di.WorkManagerProvider
+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.TimeUnit
+import javax.inject.Inject
 
-internal interface LiveLocationAggregationProcessor {
-    fun handleBeaconInfo(
-            realm: Realm,
-            event: Event,
-            content: MessageBeaconInfoContent,
-            roomId: String,
-            isLocalEcho: Boolean,
-    )
+// TODO add unit tests
+internal class LiveLocationAggregationProcessor @Inject constructor(
+        @SessionId private val sessionId: String,
+        private val workManagerProvider: WorkManagerProvider,
+        private val clock: Clock,
+) {
+
+    fun handleBeaconInfo(realm: Realm, event: Event, content: MessageBeaconInfoContent, roomId: String, isLocalEcho: Boolean) {
+        if (event.senderId.isNullOrEmpty() || isLocalEcho) {
+            return
+        }
+
+        val isLive = content.isLive.orTrue()
+        val targetEventId = if (isLive) {
+            event.eventId
+        } else {
+            // when live is set to false, we use the id of the event that should have been replaced
+            event.unsignedData?.replacesState
+        }
+
+        if (targetEventId.isNullOrEmpty()) {
+            Timber.w("no target event id found for the beacon content")
+            return
+        }
+
+        val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate(
+                realm = realm,
+                roomId = roomId,
+                eventId = targetEventId
+        )
+
+        // remote event can stay with isLive == true while the local summary is no more active
+        val isActive = aggregatedSummary.isActive.orTrue() && isLive
+        val endOfLiveTimestampMillis = content.getBestTimestampMillis()?.let { it + (content.timeout ?: 0) }
+        Timber.d("updating summary of id=$targetEventId with isActive=$isActive and endTimestamp=$endOfLiveTimestampMillis")
+
+        aggregatedSummary.endOfLiveTimestampMillis = endOfLiveTimestampMillis
+        aggregatedSummary.isActive = isActive
+        aggregatedSummary.userId = event.senderId
+
+        deactivateAllPreviousBeacons(realm, roomId, event.senderId, targetEventId)
+
+        if (isActive) {
+            scheduleDeactivationAfterTimeout(targetEventId, roomId, endOfLiveTimestampMillis)
+        } else {
+            cancelDeactivationAfterTimeout(targetEventId, roomId)
+        }
+    }
+
+    private fun scheduleDeactivationAfterTimeout(eventId: String, roomId: String, endOfLiveTimestampMillis: Long?) {
+        endOfLiveTimestampMillis ?: return
+
+        val workParams = DeactivateLiveLocationShareWorker.Params(sessionId = sessionId, eventId = eventId, roomId = roomId)
+        val workData = WorkerParamsFactory.toData(workParams)
+        val workName = DeactivateLiveLocationShareWorker.getWorkName(eventId = eventId, roomId = roomId)
+        val workDelayMillis = (endOfLiveTimestampMillis - clock.epochMillis()).coerceAtLeast(0)
+        Timber.d("scheduling deactivation of $eventId after $workDelayMillis millis")
+        val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<DeactivateLiveLocationShareWorker>()
+                .setInitialDelay(workDelayMillis, TimeUnit.MILLISECONDS)
+                .setInputData(workData)
+                .build()
+
+        workManagerProvider.workManager.enqueueUniqueWork(
+                workName,
+                ExistingWorkPolicy.REPLACE,
+                workRequest
+        )
+    }
+
+    private fun cancelDeactivationAfterTimeout(eventId: String, roomId: String) {
+        val workName = DeactivateLiveLocationShareWorker.getWorkName(eventId = eventId, roomId = roomId)
+        workManagerProvider.workManager.cancelUniqueWork(workName)
+    }
 
     fun handleBeaconLocationData(
             realm: Realm,
             event: Event,
             content: MessageBeaconLocationDataContent,
             roomId: String,
-            isLocalEcho: Boolean,
-    )
+            relatedEventId: String?,
+            isLocalEcho: Boolean
+    ) {
+        if (event.senderId.isNullOrEmpty() || isLocalEcho) {
+            return
+        }
+
+        if (relatedEventId.isNullOrEmpty()) {
+            Timber.w("no related event id found for the live location content")
+            return
+        }
+
+        val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate(
+                realm = realm,
+                roomId = roomId,
+                eventId = relatedEventId
+        )
+        val updatedLocationTimestamp = content.getBestTimestampMillis() ?: 0
+        val currentLocationTimestamp = ContentMapper
+                .map(aggregatedSummary.lastLocationContent)
+                .toModel<MessageBeaconLocationDataContent>()
+                ?.getBestTimestampMillis()
+                ?: 0
+
+        if (updatedLocationTimestamp.isMoreRecentThan(currentLocationTimestamp)) {
+            Timber.d("updating last location of the summary of id=$relatedEventId")
+            aggregatedSummary.lastLocationContent = ContentMapper.map(content.toContent())
+        }
+    }
+
+    private fun deactivateAllPreviousBeacons(realm: Realm, roomId: String, userId: String, currentEventId: String) {
+        LiveLocationShareAggregatedSummaryEntity
+                .findActiveLiveInRoomForUser(
+                        realm = realm,
+                        roomId = roomId,
+                        userId = userId,
+                        ignoredEventId = currentEventId
+                )
+                .forEach { it.isActive = false }
+    }
+
+    private fun Long.isMoreRecentThan(timestamp: Long) = this > timestamp
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/DefaultPollAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/DefaultPollAggregationProcessor.kt
new file mode 100644
index 0000000000000000000000000000000000000000..90d8e02c3930aead2965618329978d4bf570ae46
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/DefaultPollAggregationProcessor.kt
@@ -0,0 +1,205 @@
+/*
+ * 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.session.room.aggregation.poll
+
+import io.realm.Realm
+import org.matrix.android.sdk.api.extensions.orFalse
+import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.events.model.LocalEcho
+import org.matrix.android.sdk.api.session.events.model.RelationType
+import org.matrix.android.sdk.api.session.events.model.getRelationContent
+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.room.getTimelineEvent
+import org.matrix.android.sdk.api.session.room.model.PollSummaryContent
+import org.matrix.android.sdk.api.session.room.model.VoteInfo
+import org.matrix.android.sdk.api.session.room.model.VoteSummary
+import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent
+import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
+import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent
+import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
+import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
+import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
+import org.matrix.android.sdk.internal.database.mapper.ContentMapper
+import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity
+import org.matrix.android.sdk.internal.database.model.PollResponseAggregatedSummaryEntity
+import org.matrix.android.sdk.internal.database.query.create
+import org.matrix.android.sdk.internal.database.query.getOrCreate
+import org.matrix.android.sdk.internal.database.query.where
+import javax.inject.Inject
+
+class DefaultPollAggregationProcessor @Inject constructor() : PollAggregationProcessor {
+
+    override fun handlePollStartEvent(realm: Realm, event: Event): Boolean {
+        val content = event.getClearContent()?.toModel<MessagePollContent>()
+        if (content?.relatesTo?.type != RelationType.REPLACE) {
+            return false
+        }
+
+        val roomId = event.roomId ?: return false
+        val targetEventId = content.relatesTo.eventId ?: return false
+
+        EventAnnotationsSummaryEntity.getOrCreate(realm, roomId, targetEventId).let { eventAnnotationsSummaryEntity ->
+            ContentMapper
+                    .map(eventAnnotationsSummaryEntity.pollResponseSummary?.aggregatedContent)
+                    ?.toModel<PollSummaryContent>()
+                    ?.let { existingPollSummaryContent ->
+                        eventAnnotationsSummaryEntity.pollResponseSummary?.aggregatedContent = ContentMapper.map(
+                                PollSummaryContent(
+                                        myVote = existingPollSummaryContent.myVote,
+                                        votes = emptyList(),
+                                        votesSummary = emptyMap(),
+                                        totalVotes = 0,
+                                        winnerVoteCount = 0,
+                                )
+                                        .toContent()
+                        )
+                    }
+        }
+        return true
+    }
+
+    override fun handlePollResponseEvent(session: Session, realm: Realm, event: Event): Boolean {
+        val content = event.getClearContent()?.toModel<MessagePollResponseContent>() ?: return false
+        val roomId = event.roomId ?: return false
+        val senderId = event.senderId ?: return false
+        val targetEventId = (event.getRelationContent() ?: content.relatesTo)?.eventId ?: return false
+        val targetPollContent = getPollContent(session, roomId, targetEventId) ?: return false
+
+        val annotationsSummaryEntity = getAnnotationsSummaryEntity(realm, roomId, targetEventId)
+        val aggregatedPollSummaryEntity = getAggregatedPollSummaryEntity(realm, annotationsSummaryEntity)
+
+        val closedTime = aggregatedPollSummaryEntity.closedTime
+        val responseTime = event.originServerTs ?: return false
+        if (closedTime != null && responseTime > closedTime) {
+            return false
+        }
+
+        if (aggregatedPollSummaryEntity.sourceEvents.contains(event.eventId)) {
+            return false
+        }
+
+        val txId = event.unsignedData?.transactionId
+        val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "")
+        if (!isLocalEcho && aggregatedPollSummaryEntity.sourceLocalEchoEvents.contains(txId)) {
+            aggregatedPollSummaryEntity.sourceLocalEchoEvents.remove(txId)
+            aggregatedPollSummaryEntity.sourceEvents.add(event.eventId)
+            return false
+        }
+
+        val vote = content.getBestResponse()?.answers?.first() ?: return false
+        if (!targetPollContent.getBestPollCreationInfo()?.answers?.map { it.id }?.contains(vote).orFalse()) {
+            return false
+        }
+
+        val pollSummaryModel = ContentMapper.map(aggregatedPollSummaryEntity.aggregatedContent).toModel<PollSummaryContent>()
+        val existingVotes = pollSummaryModel?.votes.orEmpty().toMutableList()
+        val existingVoteIndex = existingVotes.indexOfFirst { it.userId == senderId }
+
+        if (existingVoteIndex != -1) {
+            val existingVote = existingVotes[existingVoteIndex]
+            if (existingVote.voteTimestamp > responseTime) {
+                return false
+            }
+            existingVotes[existingVoteIndex] = VoteInfo(senderId, vote, responseTime)
+        } else {
+            existingVotes.add(VoteInfo(senderId, vote, responseTime))
+        }
+
+        // Precompute the percentage of votes for all options
+        val totalVotes = existingVotes.size
+        val newVotesSummary = existingVotes
+                .groupBy({ it.option }, { it.userId })
+                .mapValues {
+                    VoteSummary(
+                            total = it.value.size,
+                            percentage = if (totalVotes == 0 && it.value.isEmpty()) 0.0 else it.value.size.toDouble() / totalVotes
+                    )
+                }
+        val newWinnerVoteCount = newVotesSummary.maxOf { it.value.total }
+
+        if (isLocalEcho) {
+            aggregatedPollSummaryEntity.sourceLocalEchoEvents.add(event.eventId)
+        } else {
+            aggregatedPollSummaryEntity.sourceEvents.add(event.eventId)
+        }
+
+        val myVote = existingVotes.find { it.userId == session.myUserId }?.option
+
+        val newSumModel = PollSummaryContent(
+                myVote = myVote,
+                votes = existingVotes,
+                votesSummary = newVotesSummary,
+                totalVotes = totalVotes,
+                winnerVoteCount = newWinnerVoteCount
+        )
+        aggregatedPollSummaryEntity.aggregatedContent = ContentMapper.map(newSumModel.toContent())
+
+        return true
+    }
+
+    override fun handlePollEndEvent(session: Session, powerLevelsHelper: PowerLevelsHelper, realm: Realm, event: Event): Boolean {
+        val content = event.getClearContent()?.toModel<MessageEndPollContent>() ?: return false
+        val roomId = event.roomId ?: return false
+        val pollEventId = content.relatesTo?.eventId ?: return false
+        val pollOwnerId = getPollEvent(session, roomId, pollEventId)?.root?.senderId
+        val isPollOwner = pollOwnerId == event.senderId
+
+        if (!isPollOwner && !powerLevelsHelper.isUserAbleToRedact(event.senderId ?: "")) {
+            return false
+        }
+
+        val annotationsSummaryEntity = getAnnotationsSummaryEntity(realm, roomId, pollEventId)
+        val aggregatedPollSummaryEntity = getAggregatedPollSummaryEntity(realm, annotationsSummaryEntity)
+
+        val txId = event.unsignedData?.transactionId
+        aggregatedPollSummaryEntity.closedTime = event.originServerTs
+
+        val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "")
+        if (!isLocalEcho && aggregatedPollSummaryEntity.sourceLocalEchoEvents.contains(txId)) {
+            aggregatedPollSummaryEntity.sourceLocalEchoEvents.remove(txId)
+            aggregatedPollSummaryEntity.sourceEvents.add(event.eventId)
+        }
+
+        return true
+    }
+
+    private fun getPollEvent(session: Session, roomId: String, eventId: String): TimelineEvent? {
+        return session.roomService().getRoom(roomId)?.getTimelineEvent(eventId)
+    }
+
+    private fun getPollContent(session: Session, roomId: String, eventId: String): MessagePollContent? {
+        val pollEvent = getPollEvent(session, roomId, eventId)
+        return pollEvent?.getLastMessageContent() as? MessagePollContent
+    }
+
+    private fun getAnnotationsSummaryEntity(realm: Realm, roomId: String, eventId: String): EventAnnotationsSummaryEntity {
+        return EventAnnotationsSummaryEntity.where(realm, roomId, eventId).findFirst()
+                ?: EventAnnotationsSummaryEntity.create(realm, roomId, eventId)
+    }
+
+    private fun getAggregatedPollSummaryEntity(
+            realm: Realm,
+            eventAnnotationsSummaryEntity: EventAnnotationsSummaryEntity
+    ): PollResponseAggregatedSummaryEntity {
+        return eventAnnotationsSummaryEntity.pollResponseSummary
+                ?: realm.createObject(PollResponseAggregatedSummaryEntity::class.java).also {
+                    eventAnnotationsSummaryEntity.pollResponseSummary = it
+                }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollAggregationProcessor.kt
new file mode 100644
index 0000000000000000000000000000000000000000..848643b435564a48c2a681009ea2d5ca004bd5db
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollAggregationProcessor.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.session.room.aggregation.poll
+
+import io.realm.Realm
+import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
+
+interface PollAggregationProcessor {
+    /**
+     * Poll start events don't need to be processed by the aggregator.
+     * This function will only handle if the poll is edited and will update the poll summary entity.
+     * Returns true if the event is aggregated.
+     */
+    fun handlePollStartEvent(
+            realm: Realm,
+            event: Event
+    ): Boolean
+
+    /**
+     * Aggregates poll response event after many conditional checks like if the poll is ended, if the user is changing his/her vote etc.
+     * Returns true if the event is aggregated.
+     */
+    fun handlePollResponseEvent(
+            session: Session,
+            realm: Realm,
+            event: Event
+    ): Boolean
+
+    /**
+     * Updates poll summary entity and mark it is ended after many conditional checks like if the poll is already ended etc.
+     * Returns true if the event is aggregated.
+     */
+    fun handlePollEndEvent(
+            session: Session,
+            powerLevelsHelper: PowerLevelsHelper,
+            realm: Realm,
+            event: Event
+    ): Boolean
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt
index 7c137a810275a1146ecb6ea5fa6e6a3531ed1713..fa19b4f9cfdd450c48b417e202ef43331bad7b42 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt
@@ -16,7 +16,7 @@
 
 package org.matrix.android.sdk.internal.session.room.alias
 
-import org.matrix.android.sdk.api.MatrixPatterns.getDomain
+import org.matrix.android.sdk.api.MatrixPatterns.getServerName
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
 import org.matrix.android.sdk.internal.di.UserId
@@ -65,6 +65,6 @@ internal class RoomAliasAvailabilityChecker @Inject constructor(
     }
 
     companion object {
-        internal fun String.toFullLocalAlias(userId: String) = "#" + this + ":" + userId.getDomain()
+        internal fun String.toFullLocalAlias(userId: String) = "#" + this + ":" + userId.getServerName()
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/crypto/DefaultRoomCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/crypto/DefaultRoomCryptoService.kt
index 2546c58cc7c64974d3b3a5b921651fc1614ea435..4f0228e6a8850445fd14ebba547e2507dfb99b8f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/crypto/DefaultRoomCryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/crypto/DefaultRoomCryptoService.kt
@@ -61,10 +61,10 @@ internal class DefaultRoomCryptoService @AssistedInject constructor(
             (!force && isEncrypted() && encryptionAlgorithm() == MXCRYPTO_ALGORITHM_MEGOLM) -> {
                 throw IllegalStateException("Encryption is already enabled for this room")
             }
-            (!force && algorithm != MXCRYPTO_ALGORITHM_MEGOLM)                              -> {
+            (!force && algorithm != MXCRYPTO_ALGORITHM_MEGOLM) -> {
                 throw InvalidParameterException("Only MXCRYPTO_ALGORITHM_MEGOLM algorithm is supported")
             }
-            else                                                                            -> {
+            else -> {
                 val params = SendStateTask.Params(
                         roomId = roomId,
                         stateKey = "",
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt
index 3867e0dc8d3fe6cd589f115593385e46875d31d3..1ea8addb20c113cfb2d745ffd0a6d7702e3213e7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt
@@ -26,9 +26,10 @@ import org.matrix.android.sdk.api.session.room.send.DraftService
 import org.matrix.android.sdk.api.session.room.send.UserDraft
 import org.matrix.android.sdk.api.util.Optional
 
-internal class DefaultDraftService @AssistedInject constructor(@Assisted private val roomId: String,
-                                                               private val draftRepository: DraftRepository,
-                                                               private val coroutineDispatchers: MatrixCoroutineDispatchers
+internal class DefaultDraftService @AssistedInject constructor(
+        @Assisted private val roomId: String,
+        private val draftRepository: DraftRepository,
+        private val coroutineDispatchers: MatrixCoroutineDispatchers
 ) : DraftService {
 
     @AssistedFactory
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DraftRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DraftRepository.kt
index c8c52c4b23553aaf9a00c5f4e8c1e93dc36ae429..b672ef7e46ec1d0ba5f93377f1661431050d0dda 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DraftRepository.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DraftRepository.kt
@@ -35,8 +35,10 @@ import org.matrix.android.sdk.internal.util.awaitTransaction
 import timber.log.Timber
 import javax.inject.Inject
 
-internal class DraftRepository @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
-                                                   private val realmSessionProvider: RealmSessionProvider) {
+internal class DraftRepository @Inject constructor(
+        @SessionDatabase private val monarchy: Monarchy,
+        private val realmSessionProvider: RealmSessionProvider
+) {
 
     suspend fun saveDraft(roomId: String, userDraft: UserDraft) {
         monarchy.awaitTransaction {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/DefaultLocationSharingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/DefaultLocationSharingService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8cf6fcdfbf4e43389e62f2165e35157555e96b69
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/DefaultLocationSharingService.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.location
+
+import androidx.lifecycle.LiveData
+import com.zhuinden.monarchy.Monarchy
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import org.matrix.android.sdk.api.session.room.location.LocationSharingService
+import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
+import org.matrix.android.sdk.internal.database.mapper.LiveLocationShareAggregatedSummaryMapper
+import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
+import org.matrix.android.sdk.internal.database.query.findRunningLiveInRoom
+import org.matrix.android.sdk.internal.di.SessionDatabase
+
+// TODO add unit tests
+internal class DefaultLocationSharingService @AssistedInject constructor(
+        @Assisted private val roomId: String,
+        @SessionDatabase private val monarchy: Monarchy,
+        private val liveLocationShareAggregatedSummaryMapper: LiveLocationShareAggregatedSummaryMapper,
+) : LocationSharingService {
+
+    @AssistedFactory
+    interface Factory {
+        fun create(roomId: String): DefaultLocationSharingService
+    }
+
+    override fun getRunningLiveLocationShareSummaries(): LiveData<List<LiveLocationShareAggregatedSummary>> {
+        return monarchy.findAllMappedWithChanges(
+                { LiveLocationShareAggregatedSummaryEntity.findRunningLiveInRoom(it, roomId = roomId) },
+                { liveLocationShareAggregatedSummaryMapper.map(it) }
+        )
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt
index d3d1cb856a05e970a85ac891dbc730058d1f9475..15d0889255155dadf49bbae7c156d9ccc4a551e1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt
@@ -68,9 +68,9 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
 
     override suspend fun execute(params: LoadRoomMembersTask.Params) {
         when (getRoomMembersLoadStatus(params.roomId)) {
-            RoomMembersLoadStatusType.NONE    -> doRequest(params)
+            RoomMembersLoadStatusType.NONE -> doRequest(params)
             RoomMembersLoadStatusType.LOADING -> waitPreviousRequestToFinish(params)
-            RoomMembersLoadStatusType.LOADED  -> Unit
+            RoomMembersLoadStatusType.LOADED -> Unit
         }
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomChangeMembershipStateDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomChangeMembershipStateDataSource.kt
index 35d8cb08af62e62a75b796ce158b251c033c373e..c61625b2b1845fb46fc39ae779d1259c8ebb3af4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomChangeMembershipStateDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomChangeMembershipStateDataSource.kt
@@ -61,8 +61,8 @@ internal class RoomChangeMembershipStateDataSource @Inject constructor() {
     private fun Membership.toMembershipChangeState(): ChangeMembershipState {
         return when {
             this == Membership.JOIN -> ChangeMembershipState.Joined
-            this.isLeft()           -> ChangeMembershipState.Left
-            else                    -> ChangeMembershipState.Unknown
+            this.isLeft() -> ChangeMembershipState.Left
+            else -> ChangeMembershipState.Unknown
         }
     }
 }
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 59e0f81ece88e81435d1c866b77f492d27782104..4645bb05ab38bc5cd41de8c3d5be93fa11bfd274 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
@@ -52,8 +52,8 @@ internal class RoomDisplayNameResolver @Inject constructor(
     /**
      * Compute the room display name.
      *
-     * @param realm: the current instance of realm
-     * @param roomId: the roomId to resolve the name of.
+     * @param realm the current instance of realm
+     * @param roomId the roomId to resolve the name of.
      * @return the room display name
      */
     fun resolve(realm: Realm, roomId: String): RoomName {
@@ -110,32 +110,32 @@ internal class RoomDisplayNameResolver @Inject constructor(
             }
             val otherMembersCount = otherMembersSubset.count()
             name = when (otherMembersCount) {
-                0    -> {
+                0 -> {
                     // Get left members if any
                     val leftMembersNames = roomMembers.queryLeftRoomMembersEvent()
                             .findAll()
                             .map { displayNameResolver.getBestName(it.toMatrixItem()) }
                     roomDisplayNameFallbackProvider.getNameForEmptyRoom(roomSummary?.isDirect.orFalse(), leftMembersNames)
                 }
-                1    -> {
+                1 -> {
                     roomDisplayNameFallbackProvider.getNameFor1member(
                             resolveRoomMemberName(otherMembersSubset[0], roomMembers)
                     )
                 }
-                2    -> {
+                2 -> {
                     roomDisplayNameFallbackProvider.getNameFor2members(
                             resolveRoomMemberName(otherMembersSubset[0], roomMembers),
                             resolveRoomMemberName(otherMembersSubset[1], roomMembers)
                     )
                 }
-                3    -> {
+                3 -> {
                     roomDisplayNameFallbackProvider.getNameFor3members(
                             resolveRoomMemberName(otherMembersSubset[0], roomMembers),
                             resolveRoomMemberName(otherMembersSubset[1], roomMembers),
                             resolveRoomMemberName(otherMembersSubset[2], roomMembers)
                     )
                 }
-                4    -> {
+                4 -> {
                     roomDisplayNameFallbackProvider.getNameFor4members(
                             resolveRoomMemberName(otherMembersSubset[0], roomMembers),
                             resolveRoomMemberName(otherMembersSubset[1], roomMembers),
@@ -158,8 +158,10 @@ internal class RoomDisplayNameResolver @Inject constructor(
     }
 
     /** See [org.matrix.android.sdk.api.session.room.sender.SenderInfo.disambiguatedDisplayName]. */
-    private fun resolveRoomMemberName(roomMemberSummary: RoomMemberSummaryEntity,
-                                      roomMemberHelper: RoomMemberHelper): String {
+    private fun resolveRoomMemberName(
+            roomMemberSummary: RoomMemberSummaryEntity,
+            roomMemberHelper: RoomMemberHelper
+    ): String {
         val isUnique = roomMemberHelper.isUniqueDisplayName(roomMemberSummary.displayName)
         return if (isUnique) {
             displayNameResolver.getBestName(roomMemberSummary.toMatrixItem())
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 a1b30a0be562756ebec3d617f9e3b9119ad02305..1e36e9c6da52a350429d74038a7be2d9f6623cdf 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
@@ -34,11 +34,13 @@ internal class RoomMemberEventHandler @Inject constructor(
         @UserId private val myUserId: String
 ) {
 
-    fun handle(realm: Realm,
-               roomId: String,
-               event: Event,
-               isInitialSync: Boolean,
-               aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean {
+    fun handle(
+            realm: Realm,
+            roomId: String,
+            event: Event,
+            isInitialSync: Boolean,
+            aggregator: SyncResponsePostTreatmentAggregator? = null
+    ): Boolean {
         if (event.type != EventType.STATE_ROOM_MEMBER) {
             return false
         }
@@ -59,12 +61,14 @@ internal class RoomMemberEventHandler @Inject constructor(
         }
     }
 
-    private fun handleInitialSync(realm: Realm,
-                                  roomId: String,
-                                  currentUserId: String,
-                                  eventUserId: String,
-                                  roomMember: RoomMemberContent,
-                                  aggregator: SyncResponsePostTreatmentAggregator?): Boolean {
+    private fun handleInitialSync(
+            realm: Realm,
+            roomId: String,
+            currentUserId: String,
+            eventUserId: String,
+            roomMember: RoomMemberContent,
+            aggregator: SyncResponsePostTreatmentAggregator?
+    ): Boolean {
         if (currentUserId != eventUserId) {
             saveUserEntityLocallyIfNecessary(realm, eventUserId, roomMember)
         }
@@ -73,10 +77,12 @@ internal class RoomMemberEventHandler @Inject constructor(
         return true
     }
 
-    private fun saveRoomMemberEntityLocally(realm: Realm,
-                                            roomId: String,
-                                            userId: String,
-                                            roomMember: RoomMemberContent) {
+    private fun saveRoomMemberEntityLocally(
+            realm: Realm,
+            roomId: String,
+            userId: String,
+            roomMember: RoomMemberContent
+    ) {
         val roomMemberEntity = RoomMemberEntityFactory.create(
                 roomId,
                 userId,
@@ -96,9 +102,11 @@ internal class RoomMemberEventHandler @Inject constructor(
         return RoomMemberSummaryEntity.where(realm, roomId, userId).findFirst()?.userPresenceEntity
     }
 
-    private fun saveUserEntityLocallyIfNecessary(realm: Realm,
-                                                 userId: String,
-                                                 roomMember: RoomMemberContent) {
+    private fun saveUserEntityLocallyIfNecessary(
+            realm: Realm,
+            userId: String,
+            roomMember: RoomMemberContent
+    ) {
         if (roomMember.membership.isActive()) {
             saveUserLocally(realm, userId, roomMember)
         }
@@ -109,9 +117,11 @@ internal class RoomMemberEventHandler @Inject constructor(
         realm.insertOrUpdate(userEntity)
     }
 
-    private fun updateDirectChatsIfNecessary(roomId: String,
-                                             roomMember: RoomMemberContent,
-                                             aggregator: SyncResponsePostTreatmentAggregator?) {
+    private fun updateDirectChatsIfNecessary(
+            roomId: String,
+            roomMember: RoomMemberContent,
+            aggregator: SyncResponsePostTreatmentAggregator?
+    ) {
         // check whether this new room member event may be used to update the directs dictionary in account data
         // this is required to handle correctly invite by email in DM
         val mxId = roomMember.thirdPartyInvite?.signed?.mxid
@@ -120,12 +130,14 @@ internal class RoomMemberEventHandler @Inject constructor(
         }
     }
 
-    private fun handleIncrementalSync(realm: Realm,
-                                      roomId: String,
-                                      eventUserId: String,
-                                      roomMember: RoomMemberContent,
-                                      prevContent: Content?,
-                                      aggregator: SyncResponsePostTreatmentAggregator?): Boolean {
+    private fun handleIncrementalSync(
+            realm: Realm,
+            roomId: String,
+            eventUserId: String,
+            roomMember: RoomMemberContent,
+            prevContent: Content?,
+            aggregator: SyncResponsePostTreatmentAggregator?
+    ): Boolean {
         if (aggregator != null) {
             val previousDisplayName = prevContent?.get("displayname") as? String
             val previousAvatar = prevContent?.get("avatar_url") as? String
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 40228fe8c977a1f4372b6dca04d23ed02cde8a59..7da12a75de58a111c0cb82b6a064f3fbea06e9cc 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
@@ -33,8 +33,9 @@ import org.matrix.android.sdk.internal.database.query.where
  * It allows to get the live membership of a user.
  */
 
-internal class RoomMemberHelper(private val realm: Realm,
-                                private val roomId: String
+internal class RoomMemberHelper(
+        private val realm: Realm,
+        private val roomId: String
 ) {
 
     private val roomSummary: RoomSummaryEntity? by lazy {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/admin/MembershipAdminTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/admin/MembershipAdminTask.kt
index d2c21f352038aff9cbc9c0fff3ab87a18769719a..b07a77a18fcc24ef1b556c1f32a0a074647079e6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/admin/MembershipAdminTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/admin/MembershipAdminTask.kt
@@ -43,9 +43,9 @@ internal class DefaultMembershipAdminTask @Inject constructor(private val roomAP
         val userIdAndReason = UserIdAndReason(params.userId, params.reason)
         executeRequest(null) {
             when (params.type) {
-                MembershipAdminTask.Type.BAN   -> roomAPI.ban(params.roomId, userIdAndReason)
+                MembershipAdminTask.Type.BAN -> roomAPI.ban(params.roomId, userIdAndReason)
                 MembershipAdminTask.Type.UNBAN -> roomAPI.unban(params.roomId, userIdAndReason)
-                MembershipAdminTask.Type.KICK  -> roomAPI.kick(params.roomId, userIdAndReason)
+                MembershipAdminTask.Type.KICK -> roomAPI.kick(params.roomId, userIdAndReason)
             }
         }
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt
index 85f53e13469ebc527500e24f6bf47dad8a8df37c..d46100a3a82eca96110544bb565bec438034b4bf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt
@@ -29,9 +29,11 @@ import org.matrix.android.sdk.internal.database.model.PushRuleEntity
 import org.matrix.android.sdk.internal.database.query.where
 import org.matrix.android.sdk.internal.di.SessionDatabase
 
-internal class DefaultRoomPushRuleService @AssistedInject constructor(@Assisted private val roomId: String,
-                                                                      private val setRoomNotificationStateTask: SetRoomNotificationStateTask,
-                                                                      @SessionDatabase private val monarchy: Monarchy) :
+internal class DefaultRoomPushRuleService @AssistedInject constructor(
+        @Assisted private val roomId: String,
+        private val setRoomNotificationStateTask: SetRoomNotificationStateTask,
+        @SessionDatabase private val monarchy: Monarchy
+) :
         RoomPushRuleService {
 
     @AssistedFactory
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt
index a5a5ab58ba1736718094dd9e340904b1921351df..42b069f8fa3c120daf29fc3279058c3bfdfe553f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt
@@ -33,10 +33,10 @@ internal fun PushRuleEntity.toRoomPushRule(): RoomPushRule? {
         RuleSetKey.OVERRIDE -> {
             PushRulesMapper.map(this)
         }
-        RuleSetKey.ROOM     -> {
+        RuleSetKey.ROOM -> {
             PushRulesMapper.mapRoomRule(this)
         }
-        else                -> null
+        else -> null
     }
     return if (pushRule == null || kind == null) {
         null
@@ -47,7 +47,7 @@ internal fun PushRuleEntity.toRoomPushRule(): RoomPushRule? {
 
 internal fun RoomNotificationState.toRoomPushRule(roomId: String): RoomPushRule? {
     return when {
-        this == RoomNotificationState.ALL_MESSAGES       -> null
+        this == RoomNotificationState.ALL_MESSAGES -> null
         this == RoomNotificationState.ALL_MESSAGES_NOISY -> {
             val rule = PushRule(
                     actions = listOf(Action.Notify, Action.Sound()).toJson(),
@@ -56,7 +56,7 @@ internal fun RoomNotificationState.toRoomPushRule(roomId: String): RoomPushRule?
             )
             return RoomPushRule(RuleSetKey.ROOM, rule)
         }
-        else                                             -> {
+        else -> {
             val condition = PushCondition(
                     kind = Kind.EventMatch.value,
                     key = "room_id",
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/SetRoomNotificationStateTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/SetRoomNotificationStateTask.kt
index 021d7dbefb104ce7734f3b5fc2f2d2d83139ce91..3d51d19cba5372559226bac78d62e4c3509f8fb9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/SetRoomNotificationStateTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/SetRoomNotificationStateTask.kt
@@ -35,9 +35,11 @@ internal interface SetRoomNotificationStateTask : Task<SetRoomNotificationStateT
     )
 }
 
-internal class DefaultSetRoomNotificationStateTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
-                                                                       private val removePushRuleTask: RemovePushRuleTask,
-                                                                       private val addPushRuleTask: AddPushRuleTask) :
+internal class DefaultSetRoomNotificationStateTask @Inject constructor(
+        @SessionDatabase private val monarchy: Monarchy,
+        private val removePushRuleTask: RemovePushRuleTask,
+        private val addPushRuleTask: AddPushRuleTask
+) :
         SetRoomNotificationStateTask {
 
     override suspend fun execute(params: SetRoomNotificationStateTask.Params) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt
index 63fc26e9d6d8e502b95f68155fb573b3860e1ec2..55c7bb1ddf6fa230166b2546348ce99843f033f0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt
@@ -111,7 +111,7 @@ internal class DefaultPeekRoomTask @Inject constructor(
                     ))
                 }?.chunk?.firstOrNull { it.roomId == roomId }
             }
-            else                           -> {
+            else -> {
                 // RoomDirectoryVisibility.PRIVATE or null
                 // We cannot resolve this room :/
                 null
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 e926d6a785ab1b859508f5310fe50091fb5c2722..e33fbb56b19d72b3124d880c6dd15cb9ede3b0a3 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
@@ -145,10 +145,10 @@ internal class RedactionEventProcessor @Inject constructor() : EventInsertLivePr
     private fun computeAllowedKeys(type: String): List<String> {
         // Add filtered content, allowed keys in content depends on the event type
         return when (type) {
-            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(
+            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",
                     "users_default",
                     "events",
@@ -159,10 +159,10 @@ internal class RedactionEventProcessor @Inject constructor() : EventInsertLivePr
                     "redact",
                     "invite"
             )
-            EventType.STATE_ROOM_ALIASES         -> listOf("aliases")
+            EventType.STATE_ROOM_ALIASES -> listOf("aliases")
             EventType.STATE_ROOM_CANONICAL_ALIAS -> listOf("alias")
-            EventType.FEEDBACK                   -> listOf("type", "target_event_id")
-            else                                 -> emptyList()
+            EventType.FEEDBACK -> listOf("type", "target_event_id")
+            else -> emptyList()
         }
     }
 }
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 7b68e2a74c1b3b1efe728301bb65f4fcdcee05e9..9839a44427fcd5939e80ab13a8753528052ab85b 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
@@ -92,25 +92,31 @@ internal class DefaultRelationService @AssistedInject constructor(
         }
     }
 
-    override fun editPoll(targetEvent: TimelineEvent,
-                          pollType: PollType,
-                          question: String,
-                          options: List<String>): Cancelable {
+    override fun editPoll(
+            targetEvent: TimelineEvent,
+            pollType: PollType,
+            question: String,
+            options: List<String>
+    ): Cancelable {
         return eventEditor.editPoll(targetEvent, pollType, question, options)
     }
 
-    override fun editTextMessage(targetEvent: TimelineEvent,
-                                 msgType: String,
-                                 newBodyText: CharSequence,
-                                 newBodyAutoMarkdown: Boolean,
-                                 compatibilityBodyText: String): Cancelable {
+    override fun editTextMessage(
+            targetEvent: TimelineEvent,
+            msgType: String,
+            newBodyText: CharSequence,
+            newBodyAutoMarkdown: Boolean,
+            compatibilityBodyText: String
+    ): Cancelable {
         return eventEditor.editTextMessage(targetEvent, msgType, newBodyText, newBodyAutoMarkdown, compatibilityBodyText)
     }
 
-    override fun editReply(replyToEdit: TimelineEvent,
-                           originalTimelineEvent: TimelineEvent,
-                           newBodyText: String,
-                           compatibilityBodyText: String): Cancelable {
+    override fun editReply(
+            replyToEdit: TimelineEvent,
+            originalTimelineEvent: TimelineEvent,
+            newBodyText: String,
+            compatibilityBodyText: String
+    ): Cancelable {
         return eventEditor.editReply(replyToEdit, originalTimelineEvent, newBodyText, compatibilityBodyText)
     }
 
@@ -164,7 +170,8 @@ internal class DefaultRelationService @AssistedInject constructor(
             msgType: String,
             autoMarkdown: Boolean,
             formattedText: String?,
-            eventReplied: TimelineEvent?): Cancelable? {
+            eventReplied: TimelineEvent?
+    ): Cancelable? {
         val event = if (eventReplied != null) {
             // Reply within a thread
             eventFactory.createReplyTextEvent(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt
index 7bf7d6b587584285cdfc697337b9730c7f424377..795e9003ce6baaaed8b3c21fe6b04fc79926e613 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt
@@ -38,11 +38,13 @@ internal class EventEditor @Inject constructor(
         private val clock: Clock,
 ) {
 
-    fun editTextMessage(targetEvent: TimelineEvent,
-                        msgType: String,
-                        newBodyText: CharSequence,
-                        newBodyAutoMarkdown: Boolean,
-                        compatibilityBodyText: String): Cancelable {
+    fun editTextMessage(
+            targetEvent: TimelineEvent,
+            msgType: String,
+            newBodyText: CharSequence,
+            newBodyAutoMarkdown: Boolean,
+            compatibilityBodyText: String
+    ): Cancelable {
         val roomId = targetEvent.roomId
         if (targetEvent.root.sendState.hasFailed()) {
             // We create a new in memory event for the EventSenderProcessor but we keep the eventId of the failed event.
@@ -61,10 +63,12 @@ internal class EventEditor @Inject constructor(
         }
     }
 
-    fun editPoll(targetEvent: TimelineEvent,
-                 pollType: PollType,
-                 question: String,
-                 options: List<String>): Cancelable {
+    fun editPoll(
+            targetEvent: TimelineEvent,
+            pollType: PollType,
+            question: String,
+            options: List<String>
+    ): Cancelable {
         val roomId = targetEvent.roomId
         if (targetEvent.root.sendState.hasFailed()) {
             val editedEvent = eventFactory.createPollEvent(roomId, pollType, question, options).copy(
@@ -92,10 +96,12 @@ internal class EventEditor @Inject constructor(
         return eventSenderProcessor.postEvent(editedEvent)
     }
 
-    fun editReply(replyToEdit: TimelineEvent,
-                  originalTimelineEvent: TimelineEvent,
-                  newBodyText: String,
-                  compatibilityBodyText: String): Cancelable {
+    fun editReply(
+            replyToEdit: TimelineEvent,
+            originalTimelineEvent: TimelineEvent,
+            newBodyText: String,
+            compatibilityBodyText: String
+    ): Cancelable {
         val roomId = replyToEdit.roomId
         if (replyToEdit.root.sendState.hasFailed()) {
             // We create a new in memory event for the EventSenderProcessor but we keep the eventId of the failed event.
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FindReactionEventForUndoTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FindReactionEventForUndoTask.kt
index f7cfa3489d347ae28325292728db2aef24002eef..585f896f32f2d3d0f8b01e78d81788975bf18f0f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FindReactionEventForUndoTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FindReactionEventForUndoTask.kt
@@ -41,7 +41,8 @@ internal interface FindReactionEventForUndoTask : Task<FindReactionEventForUndoT
 
 internal class DefaultFindReactionEventForUndoTask @Inject constructor(
         @SessionDatabase private val monarchy: Monarchy,
-        @UserId private val userId: String) : FindReactionEventForUndoTask {
+        @UserId private val userId: String
+) : FindReactionEventForUndoTask {
 
     override suspend fun execute(params: FindReactionEventForUndoTask.Params): FindReactionEventForUndoTask.Result {
         val eventId = Realm.getInstance(monarchy.realmConfiguration).use { realm ->
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/UpdateQuickReactionTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/UpdateQuickReactionTask.kt
index d0ab430dad7adf7649fa311f4894b3a9a515d491..24e8ba7f9e51d7fe33376559dd9fdf154e019355 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/UpdateQuickReactionTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/UpdateQuickReactionTask.kt
@@ -41,8 +41,10 @@ internal interface UpdateQuickReactionTask : Task<UpdateQuickReactionTask.Params
     )
 }
 
-internal class DefaultUpdateQuickReactionTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
-                                                                  @UserId private val userId: String) : UpdateQuickReactionTask {
+internal class DefaultUpdateQuickReactionTask @Inject constructor(
+        @SessionDatabase private val monarchy: Monarchy,
+        @UserId private val userId: String
+) : UpdateQuickReactionTask {
 
     override suspend fun execute(params: UpdateQuickReactionTask.Params): UpdateQuickReactionTask.Result {
         var res: Pair<String?, List<String>?>? = null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadSummariesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadSummariesTask.kt
index c5f9bd13fd59b889ea18b5e2ab6597a63a22d6df..254dee42959c6e5770888c1cea61e1066a1a03df 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadSummariesTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadSummariesTask.kt
@@ -77,8 +77,10 @@ internal class DefaultFetchThreadSummariesTask @Inject constructor(
         return handleResponse(response, params)
     }
 
-    private suspend fun handleResponse(response: PaginationResponse,
-                                       params: FetchThreadSummariesTask.Params): Result {
+    private suspend fun handleResponse(
+            response: PaginationResponse,
+            params: FetchThreadSummariesTask.Params
+    ): Result {
         val rootThreadList = response.events
         monarchy.awaitTransaction { realm ->
             val roomEntity = RoomEntity.where(realm, roomId = params.roomId).findFirst() ?: return@awaitTransaction
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 dabdd04f60205d9e3b0c986489817e043d92c036..bad734173e84c33455141c27db2111549b3a738a 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
@@ -109,8 +109,10 @@ internal class DefaultFetchThreadTimelineTask @Inject constructor(
         return handleRelationsResponse(response, params)
     }
 
-    private suspend fun handleRelationsResponse(response: RelationsResponse,
-                                                params: FetchThreadTimelineTask.Params): Result {
+    private suspend fun handleRelationsResponse(
+            response: RelationsResponse,
+            params: FetchThreadTimelineTask.Params
+    ): Result {
         val threadList = response.chunks
         val threadRootEvent = response.originalEvent
         val hasReachEnd = response.nextBatch == null
@@ -232,9 +234,11 @@ internal class DefaultFetchThreadTimelineTask @Inject constructor(
         }
     }
 
-    private fun handleReaction(realm: Realm,
-                               event: Event,
-                               roomId: String) {
+    private fun handleReaction(
+            realm: Realm,
+            event: Event,
+            roomId: String
+    ) {
         val unsignedData = event.unsignedData ?: return
         val relatedEventId = event.eventId ?: return
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomChildRelationInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomChildRelationInfo.kt
index 5bad334afc1922ecb815fddb5e5b6a17a47116aa..fffca96acf347ab0552accd40a7110b56d27a209 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomChildRelationInfo.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomChildRelationInfo.kt
@@ -43,7 +43,6 @@ internal class RoomChildRelationInfo(
     data class SpaceChildInfo(
             val roomId: String,
             val order: String?,
-//            val autoJoin: Boolean,
             val viaServers: List<String>
     )
 
@@ -60,18 +59,13 @@ internal class RoomChildRelationInfo(
     fun getDirectChildrenDescriptions(): List<SpaceChildInfo> {
         return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_CHILD)
                 .findAll()
-//                .also {
-//                    Timber.v("## Space: Found ${it.count()} m.space.child state events for $roomId")
-//                }
                 .mapNotNull {
                     ContentMapper.map(it.root?.content).toModel<SpaceChildContent>()?.let { scc ->
-//                        Timber.v("## Space child desc state event $scc")
                         // Children where via is not present are ignored.
                         scc.via?.let { via ->
                             SpaceChildInfo(
                                     roomId = it.stateKey,
                                     order = scc.validOrder(),
-//                                    autoJoin = scc.autoJoin ?: false,
                                     viaServers = via
                             )
                         }
@@ -83,17 +77,13 @@ internal class RoomChildRelationInfo(
     fun getParentDescriptions(): List<SpaceParentInfo> {
         return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_PARENT)
                 .findAll()
-//                .also {
-//                    Timber.v("## Space: Found ${it.count()} m.space.parent state events for $roomId")
-//                }
                 .mapNotNull {
-                    ContentMapper.map(it.root?.content).toModel<SpaceParentContent>()?.let { scc ->
-//                        Timber.v("## Space parent desc state event $scc")
+                    ContentMapper.map(it.root?.content).toModel<SpaceParentContent>()?.let { spaceParentContent ->
                         // Parent where via is not present are ignored.
-                        scc.via?.let { via ->
+                        spaceParentContent.via?.let { via ->
                             SpaceParentInfo(
                                     roomId = it.stateKey,
-                                    canonical = scc.canonical ?: false,
+                                    canonical = spaceParentContent.canonical ?: false,
                                     viaServers = via,
                                     stateEventSender = it.root?.sender ?: ""
                             )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/DefaultReportingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/DefaultReportingService.kt
index c961f718ef658ea8566cea42c36ea449f034cdcb..1e32bf5e16ffa0cf611704d25f268ef1b14a2348 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/DefaultReportingService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/DefaultReportingService.kt
@@ -21,8 +21,9 @@ import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import org.matrix.android.sdk.api.session.room.reporting.ReportingService
 
-internal class DefaultReportingService @AssistedInject constructor(@Assisted private val roomId: String,
-                                                                   private val reportContentTask: ReportContentTask
+internal class DefaultReportingService @AssistedInject constructor(
+        @Assisted private val roomId: String,
+        private val reportContentTask: ReportContentTask
 ) : ReportingService {
 
     @AssistedFactory
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 8529365858e6bbaeaf34b4b1070ca18645287cde..fc78abcfd93bd355147e81fd847167c8ce87cb67 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
@@ -198,7 +198,7 @@ internal class DefaultSendService @AssistedInject constructor(
                     localEchoRepository.updateSendState(localEcho.eventId, roomId, SendState.UNSENT)
                     internalSendMedia(listOf(localEcho.root), attachmentData, true)
                 }
-                is MessageFileContent  -> {
+                is MessageFileContent -> {
                     val attachmentData = ContentAttachmentData(
                             size = messageContent.info!!.size,
                             mimeType = messageContent.mimeType,
@@ -222,7 +222,7 @@ internal class DefaultSendService @AssistedInject constructor(
                     localEchoRepository.updateSendState(localEcho.eventId, roomId, SendState.UNSENT)
                     internalSendMedia(listOf(localEcho.root), attachmentData, true)
                 }
-                else                   -> NoOpCancellable
+                else -> NoOpCancellable
             }
         }
         return NoOpCancellable
@@ -265,10 +265,11 @@ internal class DefaultSendService @AssistedInject constructor(
         }
     }
 
-    override fun sendMedias(attachments: List<ContentAttachmentData>,
-                            compressBeforeSending: Boolean,
-                            roomIds: Set<String>,
-                            rootThreadEventId: String?
+    override fun sendMedias(
+            attachments: List<ContentAttachmentData>,
+            compressBeforeSending: Boolean,
+            roomIds: Set<String>,
+            rootThreadEventId: String?
     ): Cancelable {
         return attachments.mapTo(CancelableBag()) {
             sendMedia(
@@ -280,10 +281,11 @@ internal class DefaultSendService @AssistedInject constructor(
         }
     }
 
-    override fun sendMedia(attachment: ContentAttachmentData,
-                           compressBeforeSending: Boolean,
-                           roomIds: Set<String>,
-                           rootThreadEventId: String?
+    override fun sendMedia(
+            attachment: ContentAttachmentData,
+            compressBeforeSending: Boolean,
+            roomIds: Set<String>,
+            rootThreadEventId: String?
     ): Cancelable {
         // Ensure that the event will not be send in a thread if we are a different flow.
         // Like sending files to multiple rooms
@@ -354,10 +356,12 @@ internal class DefaultSendService @AssistedInject constructor(
         return "${roomId}_$identifier"
     }
 
-    private fun createUploadMediaWork(allLocalEchos: List<Event>,
-                                      attachment: ContentAttachmentData,
-                                      isRoomEncrypted: Boolean,
-                                      compressBeforeSending: Boolean): OneTimeWorkRequest {
+    private fun createUploadMediaWork(
+            allLocalEchos: List<Event>,
+            attachment: ContentAttachmentData,
+            isRoomEncrypted: Boolean,
+            compressBeforeSending: Boolean
+    ): OneTimeWorkRequest {
         val localEchoIds = allLocalEchos.map {
             LocalEchoIdentifiers(it.roomId!!, it.eventId!!)
         }
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 d39088bd6dc54758b7449d1880b481504b89afbe..3b9ca44d18cb34826a2f5ed9518c5a74a3c94674 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
@@ -119,12 +119,14 @@ internal class LocalEchoEventFactory @Inject constructor(
         return createMessageEvent(roomId, textContent.toMessageTextContent(msgType))
     }
 
-    fun createReplaceTextEvent(roomId: String,
-                               targetEventId: String,
-                               newBodyText: CharSequence,
-                               newBodyAutoMarkdown: Boolean,
-                               msgType: String,
-                               compatibilityText: String): Event {
+    fun createReplaceTextEvent(
+            roomId: String,
+            targetEventId: String,
+            newBodyText: CharSequence,
+            newBodyAutoMarkdown: Boolean,
+            msgType: String,
+            compatibilityText: String
+    ): Event {
         return createMessageEvent(
                 roomId,
                 MessageTextContent(
@@ -138,9 +140,11 @@ internal class LocalEchoEventFactory @Inject constructor(
         )
     }
 
-    private fun createPollContent(question: String,
-                                  options: List<String>,
-                                  pollType: PollType): MessagePollContent {
+    private fun createPollContent(
+            question: String,
+            options: List<String>,
+            pollType: PollType
+    ): MessagePollContent {
         return MessagePollContent(
                 unstablePollCreationInfo = PollCreationInfo(
                         question = PollQuestion(unstableQuestion = question),
@@ -152,11 +156,13 @@ internal class LocalEchoEventFactory @Inject constructor(
         )
     }
 
-    fun createPollReplaceEvent(roomId: String,
-                               pollType: PollType,
-                               targetEventId: String,
-                               question: String,
-                               options: List<String>): Event {
+    fun createPollReplaceEvent(
+            roomId: String,
+            pollType: PollType,
+            targetEventId: String,
+            question: String,
+            options: List<String>
+    ): Event {
         val newContent = MessagePollContent(
                 relatesTo = RelationDefaultContent(RelationType.REPLACE, targetEventId),
                 newContent = createPollContent(question, options, pollType).toContent()
@@ -172,9 +178,11 @@ internal class LocalEchoEventFactory @Inject constructor(
         )
     }
 
-    fun createPollReplyEvent(roomId: String,
-                             pollEventId: String,
-                             answerId: String): Event {
+    fun createPollReplyEvent(
+            roomId: String,
+            pollEventId: String,
+            answerId: String
+    ): Event {
         val content = MessagePollResponseContent(
                 body = answerId,
                 relatesTo = RelationDefaultContent(
@@ -195,10 +203,12 @@ internal class LocalEchoEventFactory @Inject constructor(
         )
     }
 
-    fun createPollEvent(roomId: String,
-                        pollType: PollType,
-                        question: String,
-                        options: List<String>): Event {
+    fun createPollEvent(
+            roomId: String,
+            pollType: PollType,
+            question: String,
+            options: List<String>
+    ): Event {
         val content = createPollContent(question, options, pollType)
         val localId = LocalEcho.createLocalEchoId()
         return Event(
@@ -212,8 +222,10 @@ internal class LocalEchoEventFactory @Inject constructor(
         )
     }
 
-    fun createEndPollEvent(roomId: String,
-                           eventId: String): Event {
+    fun createEndPollEvent(
+            roomId: String,
+            eventId: String
+    ): Event {
         val content = MessageEndPollContent(
                 relatesTo = RelationDefaultContent(
                         type = RelationType.REFERENCE,
@@ -232,11 +244,13 @@ internal class LocalEchoEventFactory @Inject constructor(
         )
     }
 
-    fun createLocationEvent(roomId: String,
-                            latitude: Double,
-                            longitude: Double,
-                            uncertainty: Double?,
-                            isUserLocation: Boolean): Event {
+    fun createLocationEvent(
+            roomId: String,
+            latitude: Double,
+            longitude: Double,
+            uncertainty: Double?,
+            isUserLocation: Boolean
+    ): Event {
         val geoUri = buildGeoUri(latitude, longitude, uncertainty)
         val assetType = if (isUserLocation) LocationAssetType.SELF else LocationAssetType.PIN
         val content = MessageLocationContent(
@@ -250,11 +264,13 @@ internal class LocalEchoEventFactory @Inject constructor(
         return createMessageEvent(roomId, content)
     }
 
-    fun createLiveLocationEvent(beaconInfoEventId: String,
-                                roomId: String,
-                                latitude: Double,
-                                longitude: Double,
-                                uncertainty: Double?): Event {
+    fun createLiveLocationEvent(
+            beaconInfoEventId: String,
+            roomId: String,
+            latitude: Double,
+            longitude: Double,
+            uncertainty: Double?
+    ): Event {
         val geoUri = buildGeoUri(latitude, longitude, uncertainty)
         val content = MessageBeaconLocationDataContent(
                 body = geoUri,
@@ -277,13 +293,15 @@ internal class LocalEchoEventFactory @Inject constructor(
         )
     }
 
-    fun createReplaceTextOfReply(roomId: String,
-                                 eventReplaced: TimelineEvent,
-                                 originalEvent: TimelineEvent,
-                                 newBodyText: String,
-                                 autoMarkdown: Boolean,
-                                 msgType: String,
-                                 compatibilityText: String): Event {
+    fun createReplaceTextOfReply(
+            roomId: String,
+            eventReplaced: TimelineEvent,
+            originalEvent: TimelineEvent,
+            newBodyText: String,
+            autoMarkdown: Boolean,
+            msgType: String,
+            compatibilityText: String
+    ): Event {
         val permalink = permalinkFactory.createPermalink(roomId, originalEvent.root.eventId ?: "", false)
         val userLink = originalEvent.root.senderId?.let { permalinkFactory.createPermalink(it, false) } ?: ""
 
@@ -321,16 +339,17 @@ internal class LocalEchoEventFactory @Inject constructor(
         )
     }
 
-    fun createMediaEvent(roomId: String,
-                         attachment: ContentAttachmentData,
-                         rootThreadEventId: String?
+    fun createMediaEvent(
+            roomId: String,
+            attachment: ContentAttachmentData,
+            rootThreadEventId: String?
     ): Event {
         return when (attachment.type) {
-            ContentAttachmentData.Type.IMAGE         -> createImageEvent(roomId, attachment, rootThreadEventId)
-            ContentAttachmentData.Type.VIDEO         -> createVideoEvent(roomId, attachment, rootThreadEventId)
-            ContentAttachmentData.Type.AUDIO         -> createAudioEvent(roomId, attachment, isVoiceMessage = false, rootThreadEventId = rootThreadEventId)
+            ContentAttachmentData.Type.IMAGE -> createImageEvent(roomId, attachment, rootThreadEventId)
+            ContentAttachmentData.Type.VIDEO -> createVideoEvent(roomId, attachment, rootThreadEventId)
+            ContentAttachmentData.Type.AUDIO -> createAudioEvent(roomId, attachment, isVoiceMessage = false, rootThreadEventId = rootThreadEventId)
             ContentAttachmentData.Type.VOICE_MESSAGE -> createAudioEvent(roomId, attachment, isVoiceMessage = true, rootThreadEventId = rootThreadEventId)
-            ContentAttachmentData.Type.FILE          -> createFileEvent(roomId, attachment, rootThreadEventId)
+            ContentAttachmentData.Type.FILE -> createFileEvent(roomId, attachment, rootThreadEventId)
         }
     }
 
@@ -435,10 +454,11 @@ internal class LocalEchoEventFactory @Inject constructor(
         return createMessageEvent(roomId, content)
     }
 
-    private fun createAudioEvent(roomId: String,
-                                 attachment: ContentAttachmentData,
-                                 isVoiceMessage: Boolean,
-                                 rootThreadEventId: String?
+    private fun createAudioEvent(
+            roomId: String,
+            attachment: ContentAttachmentData,
+            isVoiceMessage: Boolean,
+            rootThreadEventId: String?
     ): Event {
         val content = MessageAudioContent(
                 msgType = MessageType.MSGTYPE_AUDIO,
@@ -534,7 +554,8 @@ internal class LocalEchoEventFactory @Inject constructor(
             text: CharSequence,
             msgType: String,
             autoMarkdown: Boolean,
-            formattedText: String?): Event {
+            formattedText: String?
+    ): Event {
         val content = formattedText?.let { TextContent(text.toString(), it) } ?: createTextContent(text, autoMarkdown)
         return createEvent(
                 roomId,
@@ -555,12 +576,14 @@ internal class LocalEchoEventFactory @Inject constructor(
     /**
      * Creates a reply to a regular timeline Event or a thread Event if needed.
      */
-    fun createReplyTextEvent(roomId: String,
-                             eventReplied: TimelineEvent,
-                             replyText: CharSequence,
-                             autoMarkdown: Boolean,
-                             rootThreadEventId: String? = null,
-                             showInThread: Boolean): Event? {
+    fun createReplyTextEvent(
+            roomId: String,
+            eventReplied: TimelineEvent,
+            replyText: CharSequence,
+            autoMarkdown: Boolean,
+            rootThreadEventId: String? = null,
+            showInThread: Boolean
+    ): Event? {
         // Fallbacks and event representation
         // TODO Add error/warning logs when any of this is null
         val permalink = permalinkFactory.createPermalink(eventReplied.root, false) ?: return null
@@ -662,7 +685,7 @@ internal class LocalEchoEventFactory @Inject constructor(
         when (content?.msgType) {
             MessageType.MSGTYPE_EMOTE,
             MessageType.MSGTYPE_TEXT,
-            MessageType.MSGTYPE_NOTICE     -> {
+            MessageType.MSGTYPE_NOTICE -> {
                 var formattedText: String? = null
                 if (content is MessageContentWithFormattedBody) {
                     formattedText = content.matrixFormattedBody
@@ -673,14 +696,14 @@ internal class LocalEchoEventFactory @Inject constructor(
                     TextContent(content.body, formattedText)
                 }
             }
-            MessageType.MSGTYPE_FILE       -> return TextContent("sent a file.")
-            MessageType.MSGTYPE_AUDIO      -> return TextContent("sent an audio file.")
-            MessageType.MSGTYPE_IMAGE      -> return TextContent("sent an image.")
-            MessageType.MSGTYPE_VIDEO      -> return TextContent("sent a video.")
+            MessageType.MSGTYPE_FILE -> return TextContent("sent a file.")
+            MessageType.MSGTYPE_AUDIO -> return TextContent("sent an audio file.")
+            MessageType.MSGTYPE_IMAGE -> return TextContent("sent an image.")
+            MessageType.MSGTYPE_VIDEO -> return TextContent("sent a video.")
             MessageType.MSGTYPE_POLL_START -> {
                 return TextContent((content as? MessagePollContent)?.getBestPollCreationInfo()?.question?.getBestQuestion() ?: "")
             }
-            else                           -> return TextContent(content?.body ?: "")
+            else -> return TextContent(content?.body ?: "")
         }
     }
 
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 bed590fd09816e683f0ed37738ef205813b04f75..394cb8944f451ff4fb496efa54b8600d17d468e7 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
@@ -201,7 +201,7 @@ internal class LocalEchoRepository @Inject constructor(
                                             // need to resend the attachment
                                             true
                                         }
-                                        else                      -> {
+                                        else -> {
                                             Timber.e("Cannot resend message ${event.root.getClearType()} / ${content.msgType}")
                                             false
                                         }
@@ -211,7 +211,7 @@ internal class LocalEchoRepository @Inject constructor(
                                     false
                                 }
                             }
-                            else               -> {
+                            else -> {
                                 Timber.e("Unsupported message to resend ${event.root.getClearType()}")
                                 false
                             }
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 1c0da4839ab64b3be55b7309c9f504ad55ad6169..765c282b65f09e916bb56647f1ce45f6047a96e0 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
@@ -71,7 +71,7 @@ internal class RedactEventWorker(context: Context, params: WorkerParameters, ses
                 {
                     when (it) {
                         is Failure.NetworkConnection -> Result.retry()
-                        else                         -> {
+                        else -> {
                             // TODO mark as failed to send?
                             // always return success, or the chain will be stuck for ever!
                             Result.success(
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 49bc05f40c92f632b5bd6eff298542f576981b8c..c5728ba527682bbe827f5a440f318a675441ca77 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
@@ -43,7 +43,8 @@ internal fun TextContent.toMessageTextContent(msgType: String = MessageType.MSGT
 internal fun TextContent.toThreadTextContent(
         rootThreadEventId: String,
         latestThreadEventId: String,
-        msgType: String = MessageType.MSGTYPE_TEXT): MessageTextContent {
+        msgType: String = MessageType.MSGTYPE_TEXT
+): MessageTextContent {
     return MessageTextContent(
             msgType = msgType,
             format = MessageFormat.FORMAT_MATRIX_HTML.takeIf { formattedText != null },
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/WaveFormSanitizer.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/WaveFormSanitizer.kt
index 78a03f3775c6e7aa4f3ed5134ea26cef199b9986..c7ca2e770fedb0a3d503031a139cddb06816a411 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/WaveFormSanitizer.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/WaveFormSanitizer.kt
@@ -58,7 +58,7 @@ internal class WaveFormSanitizer @Inject constructor() {
                     }
                 }
             }
-            else                                 -> {
+            else -> {
                 sizeInRangeList.addAll(waveForm)
             }
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/MentionLinkSpecComparator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/MentionLinkSpecComparator.kt
index 3d235ec4d6427b0fe3e44add63d195e5e06bdce0..db5eec7e7e8cf774f3f20cb5df217f5a1a08cccf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/MentionLinkSpecComparator.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/MentionLinkSpecComparator.kt
@@ -24,9 +24,9 @@ internal class MentionLinkSpecComparator @Inject constructor() : Comparator<Ment
         return when {
             o1.start < o2.start -> -1
             o1.start > o2.start -> 1
-            o1.end < o2.end     -> 1
-            o1.end > o2.end     -> -1
-            else                -> 0
+            o1.end < o2.end -> 1
+            o1.end > o2.end -> -1
+            else -> 0
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt
index fa2e0052abd8c197a934da65cb366074c438d2be..38bddae951d52f8a93e312060d93f9c52cf12922 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt
@@ -90,7 +90,7 @@ internal class TextPillsUtils @Inject constructor(
             // test if there is an overlap
             if (b.start in a.start until a.end) {
                 when {
-                    b.end <= a.end                    ->
+                    b.end <= a.end ->
                         // b is inside a -> b should be removed
                         remove = i + 1
                     a.end - a.start > b.end - b.start ->
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 8ef631ad36a499f148fe0c23f0e8b8d5b4ef1ae0..2c7eea1e5436d4c3fc7db5cfaa744f87f0eddfe3 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
@@ -150,13 +150,13 @@ internal class EventSenderProcessorCoroutine @Inject constructor(
                     canReachServer.set(false)
                     task.markAsFailedOrRetry(exception, 0)
                 }
-                (exception.isLimitExceededError())                                 -> {
+                (exception.isLimitExceededError()) -> {
                     task.markAsFailedOrRetry(exception, exception.getRetryDelay(3_000))
                 }
-                exception is CancellationException                                 -> {
+                exception is CancellationException -> {
                     Timber.v("## $task has been cancelled, try next task")
                 }
-                else                                                               -> {
+                else -> {
                     Timber.v("## un-retryable error for $task, try next task")
                     // this task is in error, check next one?
                     task.onTaskFailed()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt
index 301f8cb9d67f811840fd98977e1a585894063d15..c5b13043d7c5f49399ba4d18c624b5cb8c589494 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt
@@ -180,7 +180,7 @@ internal class EventSenderProcessorThread @Inject constructor(
                                         waitForNetwork()
                                     }
                                 }
-                                (exception.isLimitExceededError())                                 -> {
+                                (exception.isLimitExceededError()) -> {
                                     if (task.retryCount.getAndIncrement() >= 3) task.onTaskFailed()
                                     Timber.v("## SendThread retryLoop retryable error for $task reason: ${exception.localizedMessage}")
                                     // wait a bit
@@ -188,17 +188,17 @@ internal class EventSenderProcessorThread @Inject constructor(
                                     sleep(3_000)
                                     continue@retryLoop
                                 }
-                                exception.isTokenError()                                           -> {
+                                exception.isTokenError() -> {
                                     Timber.v("## SendThread retryLoop retryable TOKEN error, interrupt")
                                     // we can exit the loop
                                     task.onTaskFailed()
                                     throw InterruptedException()
                                 }
-                                exception is CancellationException                                 -> {
+                                exception is CancellationException -> {
                                     Timber.v("## SendThread task has been cancelled")
                                     break@retryLoop
                                 }
-                                else                                                               -> {
+                                else -> {
                                     Timber.v("## SendThread retryLoop Un-Retryable error, try next task")
                                     // this task is in error, check next one?
                                     task.onTaskFailed()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueueMemento.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueueMemento.kt
index 545fc4173729fa91381a99c4faac96a0b091e254..0eedd4bd4d42b12c314986ee04ff91cf596c8680 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueueMemento.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueueMemento.kt
@@ -35,11 +35,13 @@ import javax.inject.Inject
 
 private const val PERSISTENCE_KEY = "ManagedBySender"
 
-internal class QueueMemento @Inject constructor(context: Context,
-                                                @SessionId sessionId: String,
-                                                private val queuedTaskFactory: QueuedTaskFactory,
-                                                private val localEchoRepository: LocalEchoRepository,
-                                                private val cryptoService: CryptoService) {
+internal class QueueMemento @Inject constructor(
+        context: Context,
+        @SessionId sessionId: String,
+        private val queuedTaskFactory: QueuedTaskFactory,
+        private val localEchoRepository: LocalEchoRepository,
+        private val cryptoService: CryptoService
+) {
 
     private val storage = context.getSharedPreferences("QueueMemento_$sessionId", Context.MODE_PRIVATE)
     private val trackedTasks = mutableListOf<QueuedTask>()
@@ -74,11 +76,11 @@ internal class QueueMemento @Inject constructor(context: Context,
                     encrypt = task.encrypt,
                     order = order
             )
-            is RedactQueuedTask    -> RedactEventTaskInfo(
+            is RedactQueuedTask -> RedactEventTaskInfo(
                     redactionLocalEcho = task.redactionLocalEchoId,
                     order = order
             )
-            else                   -> null
+            else -> null
         }
     }
 
@@ -92,7 +94,7 @@ internal class QueueMemento @Inject constructor(context: Context,
                 ?.forEach { info ->
                     try {
                         when (info) {
-                            is SendEventTaskInfo   -> {
+                            is SendEventTaskInfo -> {
                                 localEchoRepository.getUpToDateEcho(info.localEchoId)?.let {
                                     if (it.sendState.isSending() && it.eventId != null && it.roomId != null) {
                                         localEchoRepository.updateSendState(it.eventId, it.roomId, SendState.UNSENT)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueuedTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueuedTask.kt
index 948786677d4803cb43a040b5c75f1ab77b7fdc1f..983701857f05fa5e246cd9bed26681e105b70640 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueuedTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueuedTask.kt
@@ -21,8 +21,8 @@ import timber.log.Timber
 import java.util.concurrent.atomic.AtomicInteger
 
 /**
- * @param queueIdentifier String value to identify a unique Queue
- * @param taskIdentifier String value to identify a unique Task. Should be different from queueIdentifier
+ * @property queueIdentifier String value to identify a unique Queue
+ * @property taskIdentifier String value to identify a unique Task. Should be different from queueIdentifier
  */
 internal abstract class QueuedTask(
         val queueIdentifier: String,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/SendEventQueuedTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/SendEventQueuedTask.kt
index 49492e79907dd44fc1735b760b7ccd5f63772403..1ba4e09cafc0e3c3cd2b7a020c4490b4a76bd11b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/SendEventQueuedTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/SendEventQueuedTask.kt
@@ -45,7 +45,7 @@ internal class SendEventQueuedTask(
                 localEchoRepository.deleteFailedEchoAsync(eventId = event.eventId, roomId = event.roomId ?: "")
                 // TODO update aggregation :/ or it will stay locally
             }
-            else               -> {
+            else -> {
                 localEchoRepository.updateSendState(event.eventId!!, event.roomId, SendState.UNDELIVERED)
             }
         }
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 60231892e104ddf9ef784d0a5bfd18bba898aeae..2a980f32863e77ac2a4bf38d3d2330599a449942 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
@@ -41,11 +41,12 @@ import org.matrix.android.sdk.api.util.Optional
 import org.matrix.android.sdk.internal.session.content.FileUploader
 import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder
 
-internal class DefaultStateService @AssistedInject constructor(@Assisted private val roomId: String,
-                                                               private val stateEventDataSource: StateEventDataSource,
-                                                               private val sendStateTask: SendStateTask,
-                                                               private val fileUploader: FileUploader,
-                                                               private val viaParameterFinder: ViaParameterFinder
+internal class DefaultStateService @AssistedInject constructor(
+        @Assisted private val roomId: String,
+        private val stateEventDataSource: StateEventDataSource,
+        private val sendStateTask: SendStateTask,
+        private val fileUploader: FileUploader,
+        private val viaParameterFinder: ViaParameterFinder
 ) : StateService {
 
     @AssistedFactory
@@ -87,7 +88,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
         // Safe treatment for PowerLevelContent
         return when (eventType) {
             EventType.STATE_ROOM_POWER_LEVELS -> toSafePowerLevelsContentDict()
-            else                              -> this
+            else -> this
         }
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt
index 42d6677409472eceb21143af01eabc79f5e8628d..18c709adf2d2b3f1ac470ec672bd525632715203 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt
@@ -76,10 +76,11 @@ internal class StateEventDataSource @Inject constructor(
         }
     }
 
-    private fun buildStateEventQuery(realm: Realm,
-                                     roomId: String,
-                                     eventTypes: Set<String>,
-                                     stateKey: QueryStringValue
+    private fun buildStateEventQuery(
+            realm: Realm,
+            roomId: String,
+            eventTypes: Set<String>,
+            stateKey: QueryStringValue
     ): RealmQuery<CurrentStateEventEntity> {
         return with(queryStringValueProcessor) {
             realm.where<CurrentStateEventEntity>()
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 496bc7097fe1e6b910e50d47bf9d81778e4320a2..f10479d873aa1e6c2ebd360743c86fee8a40ce3a 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
@@ -101,11 +101,11 @@ internal class Graph {
                         // it's a candidate
                         destination = it.destination
                     }
-                    inPath     -> {
+                    inPath -> {
                         // Cycle!!
                         backwardEdges.add(it)
                     }
-                    completed  -> {
+                    completed -> {
                         // dead end
                     }
                 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/HierarchyLiveDataHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/HierarchyLiveDataHelper.kt
index 29db8431fd117c12703ef37c2801aee34c24630a..b141dfffa7044c047536ce76af0b426b151402f3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/HierarchyLiveDataHelper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/HierarchyLiveDataHelper.kt
@@ -24,7 +24,8 @@ import org.matrix.android.sdk.api.util.Optional
 internal class HierarchyLiveDataHelper(
         val spaceId: String,
         val memberships: List<Membership>,
-        val roomSummaryDataSource: RoomSummaryDataSource) {
+        val roomSummaryDataSource: RoomSummaryDataSource
+) {
 
     private val sources = HashMap<String, LiveData<Optional<RoomSummary>>>()
     private val mediatorLiveData = MediatorLiveData<List<String>>()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
index 96e8d3c73f451c8ea1fa2c412258df8710ff3a83..cb7dc270e8c47085e6501631d0a30a77738ccc56 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt
@@ -26,8 +26,9 @@ import com.zhuinden.monarchy.Monarchy
 import io.realm.Realm
 import io.realm.RealmQuery
 import io.realm.kotlin.where
-import org.matrix.android.sdk.api.query.ActiveSpaceFilter
+import org.matrix.android.sdk.api.query.QueryStringValue
 import org.matrix.android.sdk.api.query.RoomCategoryFilter
+import org.matrix.android.sdk.api.query.SpaceFilter
 import org.matrix.android.sdk.api.query.isNormalized
 import org.matrix.android.sdk.api.session.room.ResultBoundaries
 import org.matrix.android.sdk.api.session.room.RoomSortOrder
@@ -84,16 +85,20 @@ internal class RoomSummaryDataSource @Inject constructor(
         }
     }
 
-    fun getRoomSummaries(queryParams: RoomSummaryQueryParams,
-                         sortOrder: RoomSortOrder = RoomSortOrder.NONE): List<RoomSummary> {
+    fun getRoomSummaries(
+            queryParams: RoomSummaryQueryParams,
+            sortOrder: RoomSortOrder = RoomSortOrder.NONE
+    ): List<RoomSummary> {
         return monarchy.fetchAllMappedSync(
                 { roomSummariesQuery(it, queryParams).process(sortOrder) },
                 { roomSummaryMapper.map(it) }
         )
     }
 
-    fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams,
-                             sortOrder: RoomSortOrder = RoomSortOrder.NONE): LiveData<List<RoomSummary>> {
+    fun getRoomSummariesLive(
+            queryParams: RoomSummaryQueryParams,
+            sortOrder: RoomSortOrder = RoomSortOrder.NONE
+    ): LiveData<List<RoomSummary>> {
         return monarchy.findAllMappedWithChanges(
                 {
                     roomSummariesQuery(it, queryParams).process(sortOrder)
@@ -102,8 +107,10 @@ internal class RoomSummaryDataSource @Inject constructor(
         )
     }
 
-    fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams,
-                              sortOrder: RoomSortOrder = RoomSortOrder.NONE): LiveData<List<RoomSummary>> {
+    fun getSpaceSummariesLive(
+            queryParams: SpaceSummaryQueryParams,
+            sortOrder: RoomSortOrder = RoomSortOrder.NONE
+    ): LiveData<List<RoomSummary>> {
         return getRoomSummariesLive(queryParams, sortOrder)
     }
 
@@ -128,8 +135,10 @@ internal class RoomSummaryDataSource @Inject constructor(
         }
     }
 
-    fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams,
-                          sortOrder: RoomSortOrder = RoomSortOrder.NONE): List<RoomSummary> {
+    fun getSpaceSummaries(
+            spaceSummaryQueryParams: SpaceSummaryQueryParams,
+            sortOrder: RoomSortOrder = RoomSortOrder.NONE
+    ): List<RoomSummary> {
         return getRoomSummaries(spaceSummaryQueryParams, sortOrder)
     }
 
@@ -170,9 +179,11 @@ internal class RoomSummaryDataSource @Inject constructor(
                 .sort(RoomSummaryEntityFields.BREADCRUMBS_INDEX)
     }
 
-    fun getSortedPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
-                                        pagedListConfig: PagedList.Config,
-                                        sortOrder: RoomSortOrder): LiveData<PagedList<RoomSummary>> {
+    fun getSortedPagedRoomSummariesLive(
+            queryParams: RoomSummaryQueryParams,
+            pagedListConfig: PagedList.Config,
+            sortOrder: RoomSortOrder
+    ): LiveData<PagedList<RoomSummary>> {
         val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
             roomSummariesQuery(realm, queryParams).process(sortOrder)
         }
@@ -185,15 +196,18 @@ internal class RoomSummaryDataSource @Inject constructor(
         )
     }
 
-    fun getUpdatablePagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
-                                           pagedListConfig: PagedList.Config,
-                                           sortOrder: RoomSortOrder): UpdatableLivePageResult {
+    fun getUpdatablePagedRoomSummariesLive(
+            queryParams: RoomSummaryQueryParams,
+            pagedListConfig: PagedList.Config,
+            sortOrder: RoomSortOrder,
+            getFlattenedParents: Boolean = false
+    ): UpdatableLivePageResult {
         val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
             roomSummariesQuery(realm, queryParams).process(sortOrder)
         }
         val dataSourceFactory = realmDataSourceFactory.map {
             roomSummaryMapper.map(it)
-        }
+        }.map { if (getFlattenedParents) it.getWithParents() else it }
 
         val boundaries = MutableLiveData(ResultBoundaries())
 
@@ -232,6 +246,13 @@ internal class RoomSummaryDataSource @Inject constructor(
         }
     }
 
+    private fun RoomSummary.getWithParents(): RoomSummary {
+        val parents = flattenParentIds.mapNotNull { parentId ->
+            getRoomSummary(parentId)
+        }
+        return copy(flattenParents = parents)
+    }
+
     fun getCountLive(queryParams: RoomSummaryQueryParams): LiveData<Int> {
         val liveRooms = monarchy.findAllManagedWithChanges {
             roomSummariesQuery(it, queryParams)
@@ -258,29 +279,13 @@ internal class RoomSummaryDataSource @Inject constructor(
     private fun roomSummariesQuery(realm: Realm, queryParams: RoomSummaryQueryParams): RealmQuery<RoomSummaryEntity> {
         val query = with(queryStringValueProcessor) {
             RoomSummaryEntity.where(realm)
-                    .process(RoomSummaryEntityFields.ROOM_ID, queryParams.roomId)
-                    .let {
-                        if (queryParams.displayName.isNormalized()) {
-                            it.process(RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME, queryParams.displayName)
-                        } else {
-                            it.process(RoomSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
-                        }
-                    }
+                    .process(RoomSummaryEntityFields.ROOM_ID, QueryStringValue.IsNotEmpty)
+                    .process(queryParams.displayName.toDisplayNameField(), queryParams.displayName)
                     .process(RoomSummaryEntityFields.CANONICAL_ALIAS, queryParams.canonicalAlias)
                     .process(RoomSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
                     .equalTo(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, false)
         }
 
-        queryParams.roomCategoryFilter?.let {
-            when (it) {
-                RoomCategoryFilter.ONLY_DM                 -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true)
-                RoomCategoryFilter.ONLY_ROOMS              -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false)
-                RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS -> query.greaterThan(RoomSummaryEntityFields.NOTIFICATION_COUNT, 0)
-                RoomCategoryFilter.ALL                     -> {
-                    // nop
-                }
-            }
-        }
         queryParams.roomTagQueryFilter?.let {
             it.isFavorite?.let { fav ->
                 query.equalTo(RoomSummaryEntityFields.IS_FAVOURITE, fav)
@@ -300,31 +305,27 @@ internal class RoomSummaryDataSource @Inject constructor(
             query.equalTo(RoomSummaryEntityFields.ROOM_TYPE, it)
         }
         when (queryParams.roomCategoryFilter) {
-            RoomCategoryFilter.ONLY_DM                 -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true)
-            RoomCategoryFilter.ONLY_ROOMS              -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false)
+            RoomCategoryFilter.ONLY_DM -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true)
+            RoomCategoryFilter.ONLY_ROOMS -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false)
             RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS -> query.greaterThan(RoomSummaryEntityFields.NOTIFICATION_COUNT, 0)
-            RoomCategoryFilter.ALL                     -> Unit // nop
-            null                                       -> Unit
+            null -> Unit
         }
 
         // Timber.w("VAL: activeSpaceId : ${queryParams.activeSpaceId}")
-        when (queryParams.activeSpaceFilter) {
-            is ActiveSpaceFilter.ActiveSpace  -> {
+        when (queryParams.spaceFilter) {
+            SpaceFilter.OrphanRooms -> {
+                // orphan rooms
+                query.isNull(RoomSummaryEntityFields.FLATTEN_PARENT_IDS)
+            }
+            is SpaceFilter.ActiveSpace -> {
                 // It's annoying but for now realm java does not support querying in primitive list :/
                 // https://github.com/realm/realm-java/issues/5361
-                if (queryParams.activeSpaceFilter.currentSpaceId == null) {
-                    // orphan rooms
-                    query.isNull(RoomSummaryEntityFields.FLATTEN_PARENT_IDS)
-                } else {
-                    query.contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, queryParams.activeSpaceFilter.currentSpaceId)
-                }
-            }
-            is ActiveSpaceFilter.ExcludeSpace -> {
-                query.not().contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, queryParams.activeSpaceFilter.spaceId)
+                query.contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, queryParams.spaceFilter.spaceId)
             }
-            else                              -> {
-                // nop
+            is SpaceFilter.ExcludeSpace -> {
+                query.not().contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, queryParams.spaceFilter.spaceId)
             }
+            null -> Unit // nop
         }
 
         queryParams.activeGroupId?.let { activeGroupId ->
@@ -333,6 +334,14 @@ internal class RoomSummaryDataSource @Inject constructor(
         return query
     }
 
+    private fun QueryStringValue.toDisplayNameField(): String {
+        return if (isNormalized()) {
+            RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME
+        } else {
+            RoomSummaryEntityFields.DISPLAY_NAME
+        }
+    }
+
     fun getAllRoomSummaryChildOf(spaceAliasOrId: String, memberShips: List<Membership>): List<RoomSummary> {
         val space = getSpaceSummary(spaceAliasOrId) ?: return emptyList()
         val result = ArrayList<RoomSummary>()
@@ -427,11 +436,13 @@ internal class RoomSummaryDataSource @Inject constructor(
         }
     }
 
-    fun flattenSubSpace(current: RoomSummary,
-                        parenting: List<String>,
-                        output: MutableList<RoomSummary>,
-                        memberShips: List<Membership>,
-                        includeCurrent: Boolean = true) {
+    fun flattenSubSpace(
+            current: RoomSummary,
+            parenting: List<String>,
+            output: MutableList<RoomSummary>,
+            memberShips: List<Membership>,
+            includeCurrent: Boolean = true
+    ) {
         if (includeCurrent) {
             output.add(current)
         }
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 611d6dc65e7a84b70885ab60eb21d92962fb613e..e4afe7aa49dadee1905ead0a64c499e3a1dcd33f 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
@@ -85,13 +85,15 @@ internal class RoomSummaryUpdater @Inject constructor(
         }
     }
 
-    fun update(realm: Realm,
-               roomId: String,
-               membership: Membership? = null,
-               roomSummary: RoomSyncSummary? = null,
-               unreadNotifications: RoomSyncUnreadNotifications? = null,
-               updateMembers: Boolean = false,
-               inviterId: String? = null) {
+    fun update(
+            realm: Realm,
+            roomId: String,
+            membership: Membership? = null,
+            roomSummary: RoomSyncSummary? = null,
+            unreadNotifications: RoomSyncUnreadNotifications? = null,
+            updateMembers: Boolean = false,
+            inviterId: String? = null
+    ) {
         val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId)
         if (roomSummary != null) {
             if (roomSummary.heroes.isNotEmpty()) {
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 fad21c09180f9a3e8d9c9061f5201368408453e9..7795a56cbf44ce60b6a66962f05d0892dcf1b1bb 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
@@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.room.timeline
 
 import io.realm.Realm
 import io.realm.RealmConfiguration
+import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.SupervisorJob
 import kotlinx.coroutines.android.asCoroutineDispatcher
@@ -235,11 +236,15 @@ internal class DefaultTimeline(
         val loadMoreResult = try {
             strategy.loadMore(count, direction, fetchOnServerIfNeeded)
         } catch (throwable: Throwable) {
-            // Timeline could not be loaded with a (likely) permanent issue, such as the
-            // server now knowing the initialEventId, so we want to show an error message
-            // and possibly restart without initialEventId.
-            onTimelineFailure(throwable)
-            return false
+            if (throwable is CancellationException) {
+                LoadMoreResult.FAILURE
+            } else {
+                // Timeline could not be loaded with a (likely) permanent issue, such as the
+                // server now knowing the initialEventId, so we want to show an error message
+                // and possibly restart without initialEventId.
+                onTimelineFailure(throwable)
+                return false
+            }
         }
         Timber.v("$baseLogMessage: result $loadMoreResult")
         val hasMoreToLoad = loadMoreResult != LoadMoreResult.REACHED_END
@@ -259,8 +264,8 @@ internal class DefaultTimeline(
 
         strategy = when {
             rootThreadEventId != null -> buildStrategy(LoadTimelineStrategy.Mode.Thread(rootThreadEventId))
-            eventId == null           -> buildStrategy(LoadTimelineStrategy.Mode.Live)
-            else                      -> buildStrategy(LoadTimelineStrategy.Mode.Permalink(eventId))
+            eventId == null -> buildStrategy(LoadTimelineStrategy.Mode.Live)
+            else -> buildStrategy(LoadTimelineStrategy.Mode.Permalink(eventId))
         }
 
         rootThreadEventId?.let {
@@ -344,7 +349,7 @@ internal class DefaultTimeline(
 
     private fun updateState(direction: Timeline.Direction, update: (Timeline.PaginationState) -> Timeline.PaginationState) {
         val stateReference = when (direction) {
-            Timeline.Direction.FORWARDS  -> forwardState
+            Timeline.Direction.FORWARDS -> forwardState
             Timeline.Direction.BACKWARDS -> backwardState
         }
         val currentValue = stateReference.get()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveTimelineEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveTimelineEvent.kt
index e765e05578833c577c1fdcc9955318307ca04704..4be97efd6c80175082236769eb7b50f09e219aab 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveTimelineEvent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveTimelineEvent.kt
@@ -36,11 +36,13 @@ import org.matrix.android.sdk.internal.database.query.where
 /**
  * This class takes care of handling case where local echo is replaced by the synced event in the db.
  */
-internal class LiveTimelineEvent(private val monarchy: Monarchy,
-                                 private val coroutineScope: CoroutineScope,
-                                 private val timelineEventMapper: TimelineEventMapper,
-                                 private val roomId: String,
-                                 private val eventId: String) :
+internal class LiveTimelineEvent(
+        private val monarchy: Monarchy,
+        private val coroutineScope: CoroutineScope,
+        private val timelineEventMapper: TimelineEventMapper,
+        private val roomId: String,
+        private val eventId: String
+) :
         MediatorLiveData<Optional<TimelineEvent>>() {
 
     init {
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 4f65f85ce4ac31f4c03578068c5f1a3a013a5d9b..c5d4d346fdf8b82dbf7b4f490fd118468d305a41 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
@@ -267,7 +267,7 @@ internal class LoadTimelineStrategy constructor(
 
     private fun getChunkEntity(realm: Realm): RealmResults<ChunkEntity> {
         return when (mode) {
-            is Mode.Live      -> {
+            is Mode.Live -> {
                 ChunkEntity.where(realm, roomId)
                         .equalTo(ChunkEntityFields.IS_LAST_FORWARD, true)
                         .findAll()
@@ -275,7 +275,7 @@ internal class LoadTimelineStrategy constructor(
             is Mode.Permalink -> {
                 ChunkEntity.findAllIncludingEvents(realm, listOf(mode.originEventId))
             }
-            is Mode.Thread    -> {
+            is Mode.Thread -> {
                 recreateThreadChunkEntity(realm, mode.rootThreadEventId)
                 ChunkEntity.where(realm, roomId)
                         .equalTo(ChunkEntityFields.ROOT_THREAD_EVENT_ID, mode.rootThreadEventId)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationDirection.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationDirection.kt
index 930d01759e2e805a68fdb4b07685b0885bc687b6..37092de9c4155d3529f4578ef3ac084ae9f69e2f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationDirection.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationDirection.kt
@@ -31,7 +31,7 @@ internal enum class PaginationDirection(val value: String) {
 
     fun reversed(): PaginationDirection {
         return when (this) {
-            FORWARDS  -> BACKWARDS
+            FORWARDS -> BACKWARDS
             BACKWARDS -> FORWARDS
         }
     }
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 6a5f9da8a64400255e9873968c870ec393b0095d..e13f3f454fb0af42327164318f449a255053b38f 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
@@ -70,6 +70,7 @@ internal class TimelineChunk(
 
     private val isLastForward = AtomicBoolean(chunkEntity.isLastForward)
     private val isLastBackward = AtomicBoolean(chunkEntity.isLastBackward)
+    private val nextToken = chunkEntity.nextToken
     private var prevChunkLatch: CompletableDeferred<Unit>? = null
     private var nextChunkLatch: CompletableDeferred<Unit>? = null
 
@@ -136,8 +137,10 @@ internal class TimelineChunk(
             val prevEvents = prevChunk?.builtItems(includesNext = false, includesPrev = true).orEmpty()
             deepBuiltItems.addAll(prevEvents)
         }
-
-        return deepBuiltItems
+        // In some scenario (permalink) we might end up with duplicate timeline events, so we want to be sure we only expose one.
+        return deepBuiltItems.distinctBy {
+            it.eventId
+        }
     }
 
     /**
@@ -154,10 +157,6 @@ internal class TimelineChunk(
         val loadFromStorage = loadFromStorage(count, direction).also {
             logLoadedFromStorage(it, direction)
         }
-        if (loadFromStorage.numberOfEvents == 6) {
-            Timber.i("here")
-        }
-
         val offsetCount = count - loadFromStorage.numberOfEvents
 
         return if (offsetCount == 0) {
@@ -213,7 +212,7 @@ internal class TimelineChunk(
                 fetchFromServerIfNeeded -> {
                     fetchFromServer(offsetCount, chunkEntity.nextToken, direction)
                 }
-                else                    -> {
+                else -> {
                     LoadMoreResult.SUCCESS
                 }
             }
@@ -231,7 +230,7 @@ internal class TimelineChunk(
                 fetchFromServerIfNeeded -> {
                     fetchFromServer(offsetCount, chunkEntity.prevToken, direction)
                 }
-                else                    -> {
+                else -> {
                     LoadMoreResult.SUCCESS
                 }
             }
@@ -251,10 +250,6 @@ internal class TimelineChunk(
     }
 
     fun getBuiltEventIndex(eventId: String, searchInNext: Boolean, searchInPrev: Boolean): Int? {
-        val builtEventIndex = builtEventsIndexes[eventId]
-        if (builtEventIndex != null) {
-            return getOffsetIndex() + builtEventIndex
-        }
         if (searchInNext) {
             val nextBuiltEventIndex = nextChunk?.getBuiltEventIndex(eventId, searchInNext = true, searchInPrev = false)
             if (nextBuiltEventIndex != null) {
@@ -267,7 +262,12 @@ internal class TimelineChunk(
                 return prevBuiltEventIndex
             }
         }
-        return null
+        val builtEventIndex = builtEventsIndexes[eventId]
+        return if (builtEventIndex != null) {
+            getOffsetIndex() + builtEventIndex
+        } else {
+            null
+        }
     }
 
     fun getBuiltEvent(eventId: String, searchInNext: Boolean, searchInPrev: Boolean): TimelineEvent? {
@@ -445,7 +445,7 @@ internal class TimelineChunk(
             Timber.e(failure, "Failed to fetch from server")
             LoadMoreResult.FAILURE
         }
-        return if (loadMoreResult == LoadMoreResult.SUCCESS) {
+        return if (loadMoreResult != LoadMoreResult.FAILURE) {
             latch?.await()
             loadMore(count, direction, fetchOnServerIfNeeded = false)
         } else {
@@ -457,7 +457,7 @@ internal class TimelineChunk(
         return when (this) {
             TokenChunkEventPersistor.Result.REACHED_END -> LoadMoreResult.REACHED_END
             TokenChunkEventPersistor.Result.SHOULD_FETCH_MORE,
-            TokenChunkEventPersistor.Result.SUCCESS     -> LoadMoreResult.SUCCESS
+            TokenChunkEventPersistor.Result.SUCCESS -> LoadMoreResult.SUCCESS
         }
     }
 
@@ -465,16 +465,20 @@ internal class TimelineChunk(
         return when (this) {
             DefaultFetchThreadTimelineTask.Result.REACHED_END -> LoadMoreResult.REACHED_END
             DefaultFetchThreadTimelineTask.Result.SHOULD_FETCH_MORE,
-            DefaultFetchThreadTimelineTask.Result.SUCCESS     -> LoadMoreResult.SUCCESS
+            DefaultFetchThreadTimelineTask.Result.SUCCESS -> LoadMoreResult.SUCCESS
         }
     }
 
     private fun getOffsetIndex(): Int {
+        if (nextToken == null) return 0
         var offset = 0
         var currentNextChunk = nextChunk
         while (currentNextChunk != null) {
             offset += currentNextChunk.builtEvents.size
-            currentNextChunk = currentNextChunk.nextChunk
+            currentNextChunk = currentNextChunk.nextChunk?.takeIf {
+                // In case of permalink we can end up with a linked nextChunk (which is the lastForward Chunk) but no nextToken
+                it.nextToken != null
+            }
         }
         return offset
     }
@@ -486,6 +490,35 @@ internal class TimelineChunk(
     private fun handleDatabaseChangeSet(results: RealmResults<TimelineEventEntity>, changeSet: OrderedCollectionChangeSet) {
         val insertions = changeSet.insertionRanges
         for (range in insertions) {
+            // Check if the insertion's displayIndices match our expectations - or skip this insertion.
+            // Inconsistencies (missing messages) can happen otherwise if we get insertions before having loaded all timeline events of the chunk.
+            if (builtEvents.isNotEmpty()) {
+                // Check consistency to item before insertions
+                if (range.startIndex > 0) {
+                    val firstInsertion = results[range.startIndex]!!
+                    val lastBeforeInsertion = builtEvents[range.startIndex - 1]
+                    if (firstInsertion.displayIndex + 1 != lastBeforeInsertion.displayIndex) {
+                        Timber.i(
+                                "handleDatabaseChangeSet: skip insertion at ${range.startIndex}/${builtEvents.size}, " +
+                                        "displayIndex mismatch at ${range.startIndex}: ${firstInsertion.displayIndex} -> ${lastBeforeInsertion.displayIndex}"
+                        )
+                        continue
+                    }
+                }
+                // Check consistency to item after insertions
+                if (range.startIndex < builtEvents.size) {
+                    val lastInsertion = results[range.startIndex + range.length - 1]!!
+                    val firstAfterInsertion = builtEvents[range.startIndex]
+                    if (firstAfterInsertion.displayIndex + 1 != lastInsertion.displayIndex) {
+                        Timber.i(
+                                "handleDatabaseChangeSet: skip insertion at ${range.startIndex}/${builtEvents.size}, " +
+                                        "displayIndex mismatch at ${range.startIndex + range.length}: " +
+                                        "${firstAfterInsertion.displayIndex} -> ${lastInsertion.displayIndex}"
+                        )
+                        continue
+                    }
+                }
+            }
             val newItems = results
                     .subList(range.startIndex, range.startIndex + range.length)
                     .map { it.buildAndDecryptIfNeeded() }
@@ -503,8 +536,12 @@ internal class TimelineChunk(
         for (range in modifications) {
             for (modificationIndex in (range.startIndex until range.startIndex + range.length)) {
                 val updatedEntity = results[modificationIndex] ?: continue
+                val displayIndex = builtEventsIndexes[updatedEntity.eventId]
+                if (displayIndex == null) {
+                    continue
+                }
                 try {
-                    builtEvents[modificationIndex] = updatedEntity.buildAndDecryptIfNeeded()
+                    builtEvents[displayIndex] = updatedEntity.buildAndDecryptIfNeeded()
                 } catch (failure: Throwable) {
                     Timber.v("Fail to update items at index: $modificationIndex")
                 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt
index 8b58d3ca5c111064da10d2b813a68e80724b2a24..b1b9e4bb2280f5bca2451c9ed756eb286d99ea8d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt
@@ -33,10 +33,12 @@ import org.matrix.android.sdk.internal.di.SessionDatabase
 import org.matrix.android.sdk.internal.task.TaskExecutor
 import javax.inject.Inject
 
-internal class TimelineEventDataSource @Inject constructor(private val realmSessionProvider: RealmSessionProvider,
-                                                           private val timelineEventMapper: TimelineEventMapper,
-                                                           private val taskExecutor: TaskExecutor,
-                                                           @SessionDatabase private val monarchy: Monarchy) {
+internal class TimelineEventDataSource @Inject constructor(
+        private val realmSessionProvider: RealmSessionProvider,
+        private val timelineEventMapper: TimelineEventMapper,
+        private val taskExecutor: TaskExecutor,
+        @SessionDatabase private val monarchy: Monarchy
+) {
 
     fun getTimelineEvent(roomId: String, eventId: String): TimelineEvent? {
         return realmSessionProvider.withRealm { realm ->
@@ -54,7 +56,8 @@ internal class TimelineEventDataSource @Inject constructor(private val realmSess
         // TODO pretty bad query.. maybe we should denormalize clear type in base?
         return realmSessionProvider.withRealm { realm ->
             TimelineEventEntity.whereRoomId(realm, roomId)
-                    .sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING)
+                    .sort(TimelineEventEntityFields.ROOT.ORIGIN_SERVER_TS, Sort.ASCENDING)
+                    .distinct(TimelineEventEntityFields.EVENT_ID)
                     .findAll()
                     ?.mapNotNull { timelineEventMapper.map(it).takeIf { it.root.isImageMessage() || it.root.isVideoMessage() } }
                     .orEmpty()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEvent.kt
index 465b0faac8058f2c72b023192cdb07c69e1ece37..e9626a2173b62aded80135a5703238d0fee38dda 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEvent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEvent.kt
@@ -24,5 +24,5 @@ internal interface TokenChunkEvent {
     val events: List<Event>
     val stateEvents: List<Event>?
 
-    fun hasMore() = start != end
+    fun hasMore() = end != null && start != end
 }
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 96ceb6c6dca21ead391b0a860d527f79daee07df..fd1703dbc8a507a0886f5d5bfff211b91541e895 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
@@ -33,12 +33,10 @@ import org.matrix.android.sdk.internal.database.model.ChunkEntity
 import org.matrix.android.sdk.internal.database.model.EventEntity
 import org.matrix.android.sdk.internal.database.model.EventInsertType
 import org.matrix.android.sdk.internal.database.model.RoomEntity
-import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
-import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
 import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
 import org.matrix.android.sdk.internal.database.query.create
 import org.matrix.android.sdk.internal.database.query.find
-import org.matrix.android.sdk.internal.database.query.findAll
+import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom
 import org.matrix.android.sdk.internal.database.query.where
 import org.matrix.android.sdk.internal.di.SessionDatabase
 import org.matrix.android.sdk.internal.di.UserId
@@ -65,9 +63,11 @@ internal class TokenChunkEventPersistor @Inject constructor(
         SUCCESS
     }
 
-    suspend fun insertInDb(receivedChunk: TokenChunkEvent,
-                           roomId: String,
-                           direction: PaginationDirection): Result {
+    suspend fun insertInDb(
+            receivedChunk: TokenChunkEvent,
+            roomId: String,
+            direction: PaginationDirection
+    ): Result {
         monarchy
                 .awaitTransaction { realm ->
                     Timber.v("Start persisting ${receivedChunk.events.size} events in $roomId towards $direction")
@@ -81,27 +81,22 @@ internal class TokenChunkEventPersistor @Inject constructor(
                         nextToken = receivedChunk.start
                         prevToken = receivedChunk.end
                     }
-
                     val existingChunk = ChunkEntity.find(realm, roomId, prevToken = prevToken, nextToken = nextToken)
                     if (existingChunk != null) {
-                        Timber.v("This chunk is already in the db, checking if this might be caused by broken links")
-                        existingChunk.fixChunkLinks(realm, roomId, direction, prevToken, nextToken)
+                        Timber.v("This chunk is already in the db, return.")
                         return@awaitTransaction
                     }
+
+                    // Creates links in both directions
                     val prevChunk = ChunkEntity.find(realm, roomId, nextToken = prevToken)
                     val nextChunk = ChunkEntity.find(realm, roomId, prevToken = nextToken)
                     val currentChunk = ChunkEntity.create(realm, prevToken = prevToken, nextToken = nextToken).apply {
                         this.nextChunk = nextChunk
                         this.prevChunk = prevChunk
                     }
-                    val allNextChunks = ChunkEntity.findAll(realm, roomId, prevToken = nextToken)
-                    val allPrevChunks = ChunkEntity.findAll(realm, roomId, nextToken = prevToken)
-                    allNextChunks?.forEach {
-                        it.prevChunk = currentChunk
-                    }
-                    allPrevChunks?.forEach {
-                        it.nextChunk = currentChunk
-                    }
+                    nextChunk?.prevChunk = currentChunk
+                    prevChunk?.nextChunk = currentChunk
+
                     if (receivedChunk.events.isEmpty() && !receivedChunk.hasMore()) {
                         handleReachEnd(roomId, direction, currentChunk)
                     } else {
@@ -120,38 +115,13 @@ internal class TokenChunkEventPersistor @Inject constructor(
         }
     }
 
-    private fun ChunkEntity.fixChunkLinks(
-            realm: Realm,
-            roomId: String,
-            direction: PaginationDirection,
-            prevToken: String?,
-            nextToken: String?,
-    ) {
-        if (direction == PaginationDirection.FORWARDS) {
-            val prevChunks = ChunkEntity.findAll(realm, roomId, nextToken = prevToken)
-            Timber.v("Found ${prevChunks?.size} prevChunks")
-            prevChunks?.forEach {
-                if (it.nextChunk != this) {
-                    Timber.i("Set nextChunk for ${it.identifier()} from ${it.nextChunk?.identifier()} to ${identifier()}")
-                    it.nextChunk = this
-                }
-            }
-        } else {
-            val nextChunks = ChunkEntity.findAll(realm, roomId, prevToken = nextToken)
-            Timber.v("Found ${nextChunks?.size} nextChunks")
-            nextChunks?.forEach {
-                if (it.prevChunk != this) {
-                    Timber.i("Set prevChunk for ${it.identifier()} from ${it.prevChunk?.identifier()} to ${identifier()}")
-                    it.prevChunk = this
-                }
-            }
-        }
-    }
-
     private fun handleReachEnd(roomId: String, direction: PaginationDirection, currentChunk: ChunkEntity) {
-        Timber.v("Reach end of $roomId")
+        Timber.v("Reach end of $roomId in $direction")
         if (direction == PaginationDirection.FORWARDS) {
-            Timber.v("We should keep the lastForward chunk unique, the one from sync")
+            // We should keep the lastForward chunk unique, the one from sync, so make an unidirectional link.
+            // This will allow us to get live events from sync even from a permalink but won't make the link in the opposite.
+            val realm = currentChunk.realm
+            currentChunk.nextChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId)
         } else {
             currentChunk.isLastBackward = true
         }
@@ -185,38 +155,8 @@ internal class TokenChunkEventPersistor @Inject constructor(
                 if (event.eventId == null || event.senderId == null) {
                     return@forEach
                 }
-                // We check for the timeline event with this id, but not in the thread chunk
-                val eventId = event.eventId
-                val existingTimelineEvent = TimelineEventEntity
-                        .where(realm, roomId, eventId)
-                        .equalTo(TimelineEventEntityFields.OWNED_BY_THREAD_CHUNK, false)
-                        .findFirst()
-                // If it exists, we want to stop here, just link the prevChunk
-                val existingChunk = existingTimelineEvent?.chunk?.firstOrNull()
-                if (existingChunk != null) {
-                    when (direction) {
-                        PaginationDirection.BACKWARDS -> {
-                            if (currentChunk.nextChunk == existingChunk) {
-                                Timber.w("Avoid double link, shouldn't happen in an ideal world")
-                            } else {
-                                currentChunk.prevChunk = existingChunk
-                                existingChunk.nextChunk = currentChunk
-                            }
-                        }
-                        PaginationDirection.FORWARDS  -> {
-                            if (currentChunk.prevChunk == existingChunk) {
-                                Timber.w("Avoid double link, shouldn't happen in an ideal world")
-                            } else {
-                                currentChunk.nextChunk = existingChunk
-                                existingChunk.prevChunk = currentChunk
-                            }
-                        }
-                    }
-                    // Stop processing here
-                    return@processTimelineEvents
-                }
                 val ageLocalTs = event.unsignedData?.age?.let { now - it }
-                var eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, EventInsertType.PAGINATION)
+                val eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, EventInsertType.PAGINATION)
                 if (event.type == EventType.STATE_ROOM_MEMBER && event.stateKey != null) {
                     val contentToUse = if (direction == PaginationDirection.BACKWARDS) {
                         event.prevContent
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 66bb04400b320b61294fc3b3f982a5d7b8e2b56a..04c72b5d6d8340962acb22366ef2943083a5148a 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
@@ -74,7 +74,7 @@ internal class UIEchoManager(
         when (timelineEvent.root.getClearType()) {
             EventType.REDACTION -> {
             }
-            EventType.REACTION  -> {
+            EventType.REACTION -> {
                 val content: ReactionContent? = timelineEvent.root.content?.toModel<ReactionContent>()
                 if (RelationType.ANNOTATION == content?.relatesTo?.type) {
                     val reaction = content.relatesTo.key
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 12ca36fa6bb52c31f9ed620cd20145490e050b9f..5e33631f2c904fa3ad392b30c19003c6f0799379 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
@@ -24,14 +24,16 @@ internal class DefaultSearchService @Inject constructor(
         private val searchTask: SearchTask
 ) : SearchService {
 
-    override suspend fun search(searchTerm: String,
-                                roomId: String,
-                                nextBatch: String?,
-                                orderByRecent: Boolean,
-                                limit: Int,
-                                beforeLimit: Int,
-                                afterLimit: Int,
-                                includeProfile: Boolean): SearchResult {
+    override suspend fun search(
+            searchTerm: String,
+            roomId: String,
+            nextBatch: String?,
+            orderByRecent: Boolean,
+            limit: Int,
+            beforeLimit: Int,
+            afterLimit: Int,
+            includeProfile: Boolean
+    ): SearchResult {
         return searchTask.execute(
                 SearchTask.Params(
                         searchTerm = searchTerm,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt
index b5099e723874eb70aadbe87c254b6810cdac082b..4cd96c408aacfbb64e5ec8246aea118ce7230766 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt
@@ -30,6 +30,8 @@ internal interface SearchAPI {
      * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-search
      */
     @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "search")
-    suspend fun search(@Query("next_batch") nextBatch: String?,
-                       @Body body: SearchRequestBody): SearchResponse
+    suspend fun search(
+            @Query("next_batch") nextBatch: String?,
+            @Body body: SearchRequestBody
+    ): SearchResponse
 }
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 07a5cbe5a0249d26f6f26b2c4b07d37dac73e57e..8b35bd173ee35dc73993e43bb610c39d7b3ac928 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
@@ -124,7 +124,7 @@ internal class SecretStoringUtils @Inject constructor(
     fun securelyStoreString(secret: String, keyAlias: String): ByteArray {
         return when {
             buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M -> encryptStringM(secret, keyAlias)
-            else                                                      -> encryptString(secret, keyAlias)
+            else -> encryptString(secret, keyAlias)
         }
     }
 
@@ -138,8 +138,8 @@ internal class SecretStoringUtils @Inject constructor(
             // First get the format
             return when (val format = inputStream.read().toByte()) {
                 FORMAT_API_M -> decryptStringM(inputStream, keyAlias)
-                FORMAT_1     -> decryptString(inputStream, keyAlias)
-                else         -> throw IllegalArgumentException("Unknown format $format")
+                FORMAT_1 -> decryptString(inputStream, keyAlias)
+                else -> throw IllegalArgumentException("Unknown format $format")
             }
         }
     }
@@ -148,7 +148,7 @@ internal class SecretStoringUtils @Inject constructor(
     fun securelyStoreObject(any: Any, keyAlias: String, output: OutputStream) {
         when {
             buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M -> saveSecureObjectM(keyAlias, output, any)
-            else                                                      -> saveSecureObject(keyAlias, output, any)
+            else -> saveSecureObject(keyAlias, output, any)
         }
     }
 
@@ -157,8 +157,8 @@ internal class SecretStoringUtils @Inject constructor(
         // First get the format
         return when (val format = inputStream.read().toByte()) {
             FORMAT_API_M -> loadSecureObjectM(keyAlias, inputStream)
-            FORMAT_1     -> loadSecureObject(keyAlias, inputStream)
-            else         -> throw IllegalArgumentException("Unknown format $format")
+            FORMAT_1 -> loadSecureObject(keyAlias, inputStream)
+            else -> throw IllegalArgumentException("Unknown format $format")
         }
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt
index e7b20f905bb9b6e5efa3a54ee6f5c6724eb2425d..1bb86ecb4b4bc6d0b75aea02d4f595c29dfac361 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt
@@ -21,9 +21,10 @@ import org.matrix.android.sdk.api.session.signout.SignOutService
 import org.matrix.android.sdk.internal.auth.SessionParamsStore
 import javax.inject.Inject
 
-internal class DefaultSignOutService @Inject constructor(private val signOutTask: SignOutTask,
-                                                         private val signInAgainTask: SignInAgainTask,
-                                                         private val sessionParamsStore: SessionParamsStore
+internal class DefaultSignOutService @Inject constructor(
+        private val signOutTask: SignOutTask,
+        private val signInAgainTask: SignInAgainTask,
+        private val sessionParamsStore: SessionParamsStore
 ) : SignOutService {
 
     override suspend fun signInAgain(password: String) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt
index 178a29a5a01c06ea7d31de8142ad173c18b53be4..32faffa670c431faeb2c9d38b37bcb85ef9b7aaf 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt
@@ -44,11 +44,13 @@ internal class DefaultSpace(
         return spaceSummaryDataSource.getSpaceSummary(room.roomId)
     }
 
-    override suspend fun addChildren(roomId: String,
-                                     viaServers: List<String>?,
-                                     order: String?,
+    override suspend fun addChildren(
+            roomId: String,
+            viaServers: List<String>?,
+            order: String?,
 //                                     autoJoin: Boolean,
-                                     suggested: Boolean?) {
+            suggested: Boolean?
+    ) {
         // Find best via
         val bestVia = viaServers
                 ?: (spaceSummaryDataSource.getRoomSummary(roomId)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt
index 9320665688af7281e01c0182aa683be5e3516b35..c08d9389a87b5f5841b93eea8cd475b85f0d2bf9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt
@@ -99,13 +99,17 @@ internal class DefaultSpaceService @Inject constructor(
         return spaceGetter.get(spaceId)
     }
 
-    override fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams,
-                                       sortOrder: RoomSortOrder): LiveData<List<RoomSummary>> {
+    override fun getSpaceSummariesLive(
+            queryParams: SpaceSummaryQueryParams,
+            sortOrder: RoomSortOrder
+    ): LiveData<List<RoomSummary>> {
         return roomSummaryDataSource.getSpaceSummariesLive(queryParams, sortOrder)
     }
 
-    override fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams,
-                                   sortOrder: RoomSortOrder): List<RoomSummary> {
+    override fun getSpaceSummaries(
+            spaceSummaryQueryParams: SpaceSummaryQueryParams,
+            sortOrder: RoomSortOrder
+    ): List<RoomSummary> {
         return roomSummaryDataSource.getSpaceSummaries(spaceSummaryQueryParams, sortOrder)
     }
 
@@ -221,9 +225,11 @@ internal class DefaultSpaceService @Inject constructor(
             worldReadable = summary.isWorldReadable
     )
 
-    override suspend fun joinSpace(spaceIdOrAlias: String,
-                                   reason: String?,
-                                   viaServers: List<String>): JoinSpaceResult {
+    override suspend fun joinSpace(
+            spaceIdOrAlias: String,
+            reason: String?,
+            viaServers: List<String>
+    ): JoinSpaceResult {
         return joinSpaceTask.execute(JoinSpaceTask.Params(spaceIdOrAlias, reason, viaServers))
     }
 
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 d8daa55e150e2bcd64e8be5548de35a0396cabd6..126245d01559a0ecee92f9475878dff5e6ae6399 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
@@ -24,11 +24,12 @@ import retrofit2.http.Query
 internal interface SpaceApi {
 
     /**
+     * @param spaceId the space Id
      * @param suggestedOnly Optional. If true, return only child events and rooms where the m.space.child event has suggested: true.
-     * @param limit: Optional: a client-defined limit to the maximum number of rooms to return per page. Must be a non-negative integer.
-     * @param maxDepth: Optional: The maximum depth in the tree (from the root room) to return.
+     * @param limit Optional: a client-defined limit to the maximum number of rooms to return per page. Must be a non-negative integer.
+     * @param maxDepth Optional: The maximum depth in the tree (from the root room) to return.
      * The deepest depth returned will not include children events. Defaults to no-limit. Must be a non-negative integer.
-     * @param from: Optional. Pagination token given to retrieve the next set of rooms.
+     * @param from Optional. Pagination token given to retrieve the next set of rooms.
      * Note that if a pagination token is provided, then the parameters given for suggested_only and max_depth must be the same.
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_V1 + "rooms/{roomId}/hierarchy")
@@ -37,7 +38,8 @@ internal interface SpaceApi {
             @Query("suggested_only") suggestedOnly: Boolean?,
             @Query("limit") limit: Int?,
             @Query("max_depth") maxDepth: Int?,
-            @Query("from") from: String?): SpacesResponse
+            @Query("from") from: String?
+    ): SpacesResponse
 
     /**
      * Unstable version of [getSpaceHierarchy].
@@ -48,5 +50,6 @@ internal interface SpaceApi {
             @Query("suggested_only") suggestedOnly: Boolean?,
             @Query("limit") limit: Int?,
             @Query("max_depth") maxDepth: Int?,
-            @Query("from") from: String?): SpacesResponse
+            @Query("from") from: String?
+    ): SpacesResponse
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/DefaultSyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/DefaultSyncService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..37869b88f9d2688a0a53aba849998bf60aad173d
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/DefaultSyncService.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.sync
+
+import androidx.lifecycle.LiveData
+import org.matrix.android.sdk.api.session.sync.SyncRequestState
+import org.matrix.android.sdk.api.session.sync.SyncService
+import org.matrix.android.sdk.internal.di.SessionId
+import org.matrix.android.sdk.internal.di.WorkManagerProvider
+import org.matrix.android.sdk.internal.session.SessionState
+import org.matrix.android.sdk.internal.session.sync.job.SyncThread
+import org.matrix.android.sdk.internal.session.sync.job.SyncWorker
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Provider
+
+internal class DefaultSyncService @Inject constructor(
+        @SessionId val sessionId: String,
+        private val workManagerProvider: WorkManagerProvider,
+        private val syncThreadProvider: Provider<SyncThread>,
+        private val syncTokenStore: SyncTokenStore,
+        private val syncRequestStateTracker: SyncRequestStateTracker,
+        private val sessionState: SessionState,
+) : SyncService {
+    private var syncThread: SyncThread? = null
+
+    override fun requireBackgroundSync() {
+        SyncWorker.requireBackgroundSync(workManagerProvider, sessionId)
+    }
+
+    override fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long) {
+        SyncWorker.automaticallyBackgroundSync(workManagerProvider, sessionId, timeOutInSeconds, repeatDelayInSeconds)
+    }
+
+    override fun stopAnyBackgroundSync() {
+        SyncWorker.stopAnyBackgroundSync(workManagerProvider)
+    }
+
+    override fun startSync(fromForeground: Boolean) {
+        Timber.i("Starting sync thread")
+        assert(sessionState.isOpen)
+        val localSyncThread = getSyncThread()
+        localSyncThread.setInitialForeground(fromForeground)
+        if (!localSyncThread.isAlive) {
+            localSyncThread.start()
+        } else {
+            localSyncThread.restart()
+            Timber.w("Attempt to start an already started thread")
+        }
+    }
+
+    override fun stopSync() {
+        assert(sessionState.isOpen)
+        syncThread?.kill()
+        syncThread = null
+    }
+
+    override fun getSyncStateLive() = getSyncThread().liveState()
+
+    override fun syncFlow() = getSyncThread().syncFlow()
+
+    override fun getSyncState() = getSyncThread().currentState()
+
+    override fun getSyncRequestStateLive(): LiveData<SyncRequestState> {
+        return syncRequestStateTracker.syncRequestState
+    }
+
+    override fun hasAlreadySynced(): Boolean {
+        return syncTokenStore.getLastToken() != null
+    }
+
+    private fun getSyncThread(): SyncThread {
+        return syncThread ?: syncThreadProvider.get().also {
+            syncThread = it
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/Extensions.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ae542103b787679f8780a7b2b5bfc331ded21c64
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/Extensions.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 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.sync
+
+import org.matrix.android.sdk.api.session.sync.InitialSyncStep
+
+internal inline fun <T> reportSubtask(
+        reporter: ProgressReporter?,
+        initialSyncStep: InitialSyncStep,
+        totalProgress: Int,
+        parentWeight: Float,
+        block: () -> T
+): T {
+    reporter?.startTask(initialSyncStep, totalProgress, parentWeight)
+    return block().also {
+        reporter?.endTask()
+    }
+}
+
+internal inline fun <K, V, R> Map<out K, V>.mapWithProgress(
+        reporter: ProgressReporter?,
+        initialSyncStep: InitialSyncStep,
+        parentWeight: Float,
+        transform: (Map.Entry<K, V>) -> R
+): List<R> {
+    var current = 0F
+    reporter?.startTask(initialSyncStep, count() + 1, parentWeight)
+    return map {
+        reporter?.reportProgress(current)
+        current++
+        transform.invoke(it)
+    }.also {
+        reporter?.endTask()
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/ProgressReporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/ProgressReporter.kt
similarity index 74%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/ProgressReporter.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/ProgressReporter.kt
index 8a7b26b4b8fbe6d9791e044a44af83fa2e4352f7..6d77b9be5e3b1f80e3cf17405f42d82bc7bf1c17 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/ProgressReporter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/ProgressReporter.kt
@@ -14,14 +14,16 @@
  * limitations under the License.
  */
 
-package org.matrix.android.sdk.internal.session.initsync
+package org.matrix.android.sdk.internal.session.sync
 
-import org.matrix.android.sdk.api.session.initsync.InitSyncStep
+import org.matrix.android.sdk.api.session.sync.InitialSyncStep
 
 internal interface ProgressReporter {
-    fun startTask(initSyncStep: InitSyncStep,
-                  totalProgress: Int,
-                  parentWeight: Float)
+    fun startTask(
+            initialSyncStep: InitialSyncStep,
+            totalProgress: Int,
+            parentWeight: Float
+    )
 
     fun reportProgress(progress: Float)
 
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 6c8a71f35ecd02a6875d2d70fc0e9f5561eb88e6..2a2fd6ab1d889a8f7a60aece53c667b820bcf158 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
@@ -31,10 +31,11 @@ internal interface SyncAPI {
      * 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>,
-                     @Header(TimeOutInterceptor.CONNECT_TIMEOUT) connectTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT,
-                     @Header(TimeOutInterceptor.READ_TIMEOUT) readTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT,
-                     @Header(TimeOutInterceptor.WRITE_TIMEOUT) writeTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT
+    suspend fun sync(
+            @QueryMap params: Map<String, String>,
+            @Header(TimeOutInterceptor.CONNECT_TIMEOUT) connectTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT,
+            @Header(TimeOutInterceptor.READ_TIMEOUT) readTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT,
+            @Header(TimeOutInterceptor.WRITE_TIMEOUT) writeTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT
     ): SyncResponse
 
     /**
@@ -42,9 +43,10 @@ internal interface SyncAPI {
      */
     @Streaming
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "sync")
-    fun syncStream(@QueryMap params: Map<String, String>,
-                   @Header(TimeOutInterceptor.CONNECT_TIMEOUT) connectTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT,
-                   @Header(TimeOutInterceptor.READ_TIMEOUT) readTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT,
-                   @Header(TimeOutInterceptor.WRITE_TIMEOUT) writeTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT
+    fun syncStream(
+            @QueryMap params: Map<String, String>,
+            @Header(TimeOutInterceptor.CONNECT_TIMEOUT) connectTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT,
+            @Header(TimeOutInterceptor.READ_TIMEOUT) readTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT,
+            @Header(TimeOutInterceptor.WRITE_TIMEOUT) writeTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT
     ): Call<ResponseBody>
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncModule.kt
index 4b31dc4d9b00b7d9b488c0abc50604ca1c98364f..d78070439c51503c86d0cfa5d971d7c36df642e2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncModule.kt
@@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.sync
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
+import org.matrix.android.sdk.api.session.sync.SyncService
 import org.matrix.android.sdk.internal.session.SessionScope
 import retrofit2.Retrofit
 
@@ -35,6 +36,9 @@ internal abstract class SyncModule {
         }
     }
 
+    @Binds
+    abstract fun bindSyncService(service: DefaultSyncService): SyncService
+
     @Binds
     abstract fun bindSyncTask(task: DefaultSyncTask): SyncTask
 
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 ce41a4568cdf190c16a47da9739366a8c61a444b..9df6d52ad3b27b9c8fa8f1cc9b2a30daa1ae7244 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
@@ -35,9 +35,9 @@ internal enum class SyncPresence(val value: String) {
     companion object {
         fun from(presenceEnum: PresenceEnum): SyncPresence {
             return when (presenceEnum) {
-                PresenceEnum.ONLINE      -> Online
-                PresenceEnum.OFFLINE     -> Offline
-                PresenceEnum.BUSY        -> Busy
+                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/initsync/DefaultSyncStatusService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncRequestStateTracker.kt
similarity index 63%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/DefaultSyncStatusService.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncRequestStateTracker.kt
index 2aa0be80c9b4e36473adc2d433e517532b5a09c5..bcc5fcf9abe0d059e76f993e7a24352301ba3e30 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/sync/SyncRequestStateTracker.kt
@@ -13,52 +13,51 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.matrix.android.sdk.internal.session.initsync
 
-import androidx.lifecycle.LiveData
+package org.matrix.android.sdk.internal.session.sync
+
 import androidx.lifecycle.MutableLiveData
-import org.matrix.android.sdk.api.session.initsync.InitSyncStep
-import org.matrix.android.sdk.api.session.initsync.SyncStatusService
+import org.matrix.android.sdk.api.session.sync.InitialSyncStep
+import org.matrix.android.sdk.api.session.sync.SyncRequestState
 import org.matrix.android.sdk.internal.session.SessionScope
 import javax.inject.Inject
 
 @SessionScope
-internal class DefaultSyncStatusService @Inject constructor() :
-        SyncStatusService,
+internal class SyncRequestStateTracker @Inject constructor() :
         ProgressReporter {
 
-    private val status = MutableLiveData<SyncStatusService.Status>()
+    val syncRequestState = MutableLiveData<SyncRequestState>()
 
     private var rootTask: TaskInfo? = null
 
-    override fun getSyncStatusLive(): LiveData<SyncStatusService.Status> {
-        return status
-    }
-
     // Only to be used for incremental sync
-    fun setStatus(newStatus: SyncStatusService.Status.IncrementalSyncStatus) {
-        status.postValue(newStatus)
+    fun setSyncRequestState(newSyncRequestState: SyncRequestState.IncrementalSyncRequestState) {
+        syncRequestState.postValue(newSyncRequestState)
     }
 
     /**
      * Create a rootTask.
      */
-    fun startRoot(initSyncStep: InitSyncStep,
-                  totalProgress: Int) {
+    fun startRoot(
+            initialSyncStep: InitialSyncStep,
+            totalProgress: Int
+    ) {
         endAll()
-        rootTask = TaskInfo(initSyncStep, totalProgress, null, 1F)
+        rootTask = TaskInfo(initialSyncStep, totalProgress, null, 1F)
         reportProgress(0F)
     }
 
     /**
      * Add a child to the leaf.
      */
-    override fun startTask(initSyncStep: InitSyncStep,
-                           totalProgress: Int,
-                           parentWeight: Float) {
+    override fun startTask(
+            initialSyncStep: InitialSyncStep,
+            totalProgress: Int,
+            parentWeight: Float
+    ) {
         val currentLeaf = rootTask?.leaf() ?: return
         currentLeaf.child = TaskInfo(
-                initSyncStep = initSyncStep,
+                initialSyncStep = initialSyncStep,
                 totalProgress = totalProgress,
                 parent = currentLeaf,
                 parentWeight = parentWeight
@@ -72,7 +71,7 @@ internal class DefaultSyncStatusService @Inject constructor() :
                 // Update the progress of the leaf and all its parents
                 leaf.setProgress(progress)
                 // Then update the live data using leaf wording and root progress
-                status.postValue(SyncStatusService.Status.InitialSyncProgressing(leaf.initSyncStep, root.currentProgress.toInt()))
+                syncRequestState.postValue(SyncRequestState.InitialSyncProgressing(leaf.initialSyncStep, root.currentProgress.toInt()))
             }
         }
     }
@@ -87,13 +86,13 @@ internal class DefaultSyncStatusService @Inject constructor() :
                 // And close it
                 endedTask.parent.child = null
             } else {
-                status.postValue(SyncStatusService.Status.Idle)
+                syncRequestState.postValue(SyncRequestState.Idle)
             }
         }
     }
 
     fun endAll() {
         rootTask = null
-        status.postValue(SyncStatusService.Status.Idle)
+        syncRequestState.postValue(SyncRequestState.Idle)
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt
index 02a7a9a37fe13aef18d645a7e732b530c0cbb5a2..9e5302222ab3571e9c7964ce58752538874eb223 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt
@@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.session.sync
 
 import androidx.work.ExistingPeriodicWorkPolicy
 import com.zhuinden.monarchy.Monarchy
-import org.matrix.android.sdk.api.session.initsync.InitSyncStep
 import org.matrix.android.sdk.api.session.pushrules.PushRuleService
 import org.matrix.android.sdk.api.session.pushrules.RuleScope
+import org.matrix.android.sdk.api.session.sync.InitialSyncStep
 import org.matrix.android.sdk.api.session.sync.model.GroupsSyncResponse
 import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse
 import org.matrix.android.sdk.api.session.sync.model.SyncResponse
@@ -32,8 +32,6 @@ import org.matrix.android.sdk.internal.di.WorkManagerProvider
 import org.matrix.android.sdk.internal.session.SessionListeners
 import org.matrix.android.sdk.internal.session.dispatchTo
 import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker
-import org.matrix.android.sdk.internal.session.initsync.ProgressReporter
-import org.matrix.android.sdk.internal.session.initsync.reportSubtask
 import org.matrix.android.sdk.internal.session.pushrules.ProcessEventForPushTask
 import org.matrix.android.sdk.internal.session.sync.handler.CryptoSyncHandler
 import org.matrix.android.sdk.internal.session.sync.handler.GroupSyncHandler
@@ -68,9 +66,11 @@ internal class SyncResponseHandler @Inject constructor(
         private val presenceSyncHandler: PresenceSyncHandler
 ) {
 
-    suspend fun handleResponse(syncResponse: SyncResponse,
-                               fromToken: String?,
-                               reporter: ProgressReporter?) {
+    suspend fun handleResponse(
+            syncResponse: SyncResponse,
+            fromToken: String?,
+            reporter: ProgressReporter?
+    ) {
         val isInitialSync = fromToken == null
         Timber.v("Start handling sync, is InitialSync: $isInitialSync")
 
@@ -88,7 +88,7 @@ internal class SyncResponseHandler @Inject constructor(
         // to ensure to decrypt them properly
         measureTimeMillis {
             Timber.v("Handle toDevice")
-            reportSubtask(reporter, InitSyncStep.ImportingAccountCrypto, 100, 0.1f) {
+            reportSubtask(reporter, InitialSyncStep.ImportingAccountCrypto, 100, 0.1f) {
                 if (syncResponse.toDevice != null) {
                     cryptoSyncHandler.handleToDevice(syncResponse.toDevice, reporter)
                 }
@@ -109,7 +109,7 @@ internal class SyncResponseHandler @Inject constructor(
             // IMPORTANT nothing should be suspend here as we are accessing the realm instance (thread local)
             measureTimeMillis {
                 Timber.v("Handle rooms")
-                reportSubtask(reporter, InitSyncStep.ImportingAccountRoom, 1, 0.7f) {
+                reportSubtask(reporter, InitialSyncStep.ImportingAccountRoom, 1, 0.7f) {
                     if (syncResponse.rooms != null) {
                         roomSyncHandler.handle(realm, syncResponse.rooms, isInitialSync, aggregator, reporter)
                     }
@@ -119,7 +119,7 @@ internal class SyncResponseHandler @Inject constructor(
             }
 
             measureTimeMillis {
-                reportSubtask(reporter, InitSyncStep.ImportingAccountGroups, 1, 0.1f) {
+                reportSubtask(reporter, InitialSyncStep.ImportingAccountGroups, 1, 0.1f) {
                     Timber.v("Handle groups")
                     if (syncResponse.groups != null) {
                         groupSyncHandler.handle(realm, syncResponse.groups, reporter)
@@ -130,7 +130,7 @@ internal class SyncResponseHandler @Inject constructor(
             }
 
             measureTimeMillis {
-                reportSubtask(reporter, InitSyncStep.ImportingAccountData, 1, 0.1f) {
+                reportSubtask(reporter, InitialSyncStep.ImportingAccountData, 1, 0.1f) {
                     Timber.v("Handle accountData")
                     userAccountDataSyncHandler.handle(realm, syncResponse.accountData)
                 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt
index f88d9731015b2fc504ceda7e0b0782a82532a264..ea296d379ddc51feb783eb8f1f3e14b98b3218a7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt
@@ -21,10 +21,10 @@ import okhttp3.ResponseBody
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.logger.LoggerTag
 import org.matrix.android.sdk.api.session.Session
-import org.matrix.android.sdk.api.session.initsync.InitSyncStep
-import org.matrix.android.sdk.api.session.initsync.SyncStatusService
 import org.matrix.android.sdk.api.session.statistics.StatisticEvent
+import org.matrix.android.sdk.api.session.sync.InitialSyncStep
 import org.matrix.android.sdk.api.session.sync.InitialSyncStrategy
+import org.matrix.android.sdk.api.session.sync.SyncRequestState
 import org.matrix.android.sdk.api.session.sync.initialSyncStrategy
 import org.matrix.android.sdk.api.session.sync.model.LazyRoomSyncEphemeral
 import org.matrix.android.sdk.api.session.sync.model.SyncResponse
@@ -38,8 +38,6 @@ import org.matrix.android.sdk.internal.session.SessionListeners
 import org.matrix.android.sdk.internal.session.dispatchTo
 import org.matrix.android.sdk.internal.session.filter.FilterRepository
 import org.matrix.android.sdk.internal.session.homeserver.GetHomeServerCapabilitiesTask
-import org.matrix.android.sdk.internal.session.initsync.DefaultSyncStatusService
-import org.matrix.android.sdk.internal.session.initsync.reportSubtask
 import org.matrix.android.sdk.internal.session.sync.parsing.InitialSyncResponseParser
 import org.matrix.android.sdk.internal.session.user.UserStore
 import org.matrix.android.sdk.internal.task.Task
@@ -68,7 +66,7 @@ internal class DefaultSyncTask @Inject constructor(
         @UserId private val userId: String,
         private val filterRepository: FilterRepository,
         private val syncResponseHandler: SyncResponseHandler,
-        private val defaultSyncStatusService: DefaultSyncStatusService,
+        private val syncRequestStateTracker: SyncRequestStateTracker,
         private val syncTokenStore: SyncTokenStore,
         private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask,
         private val userStore: UserStore,
@@ -115,7 +113,7 @@ internal class DefaultSyncTask @Inject constructor(
                     displayName = user?.displayName,
                     avatarUrl = user?.avatarUrl
             )
-            defaultSyncStatusService.startRoot(InitSyncStep.ImportingAccount, 100)
+            syncRequestStateTracker.startRoot(InitialSyncStep.ImportingAccount, 100)
         }
         // Maybe refresh the homeserver capabilities data we know
         getHomeServerCapabilitiesTask.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false))
@@ -132,7 +130,7 @@ internal class DefaultSyncTask @Inject constructor(
                     roomSyncEphemeralTemporaryStore.reset()
                     workingDir.mkdirs()
                     val file = downloadInitSyncResponse(requestParams, syncStatisticsData)
-                    syncResponseToReturn = reportSubtask(defaultSyncStatusService, InitSyncStep.ImportingAccount, 1, 0.7F) {
+                    syncResponseToReturn = reportSubtask(syncRequestStateTracker, InitialSyncStep.ImportingAccount, 1, 0.7F) {
                         handleSyncFile(file, initSyncStrategy)
                     }
                     // Delete all files
@@ -150,15 +148,15 @@ internal class DefaultSyncTask @Inject constructor(
                     syncStatisticsData.requestInitSyncTime = SystemClock.elapsedRealtime()
                     syncStatisticsData.downloadInitSyncTime = syncStatisticsData.requestInitSyncTime
                     logDuration("INIT_SYNC Database insertion", loggerTag, clock) {
-                        syncResponseHandler.handleResponse(syncResponse, token, defaultSyncStatusService)
+                        syncResponseHandler.handleResponse(syncResponse, token, syncRequestStateTracker)
                     }
                     syncResponseToReturn = syncResponse
                 }
             }
-            defaultSyncStatusService.endAll()
+            syncRequestStateTracker.endAll()
         } else {
             Timber.tag(loggerTag.value).d("Start incremental sync request with since token $token")
-            defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncIdle)
+            syncRequestStateTracker.setSyncRequestState(SyncRequestState.IncrementalSyncIdle)
             val syncResponse = try {
                 executeRequest(globalErrorReceiver) {
                     syncAPI.sync(
@@ -168,7 +166,7 @@ internal class DefaultSyncTask @Inject constructor(
                 }
             } catch (throwable: Throwable) {
                 Timber.tag(loggerTag.value).e(throwable, "Incremental sync request error")
-                defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncError)
+                syncRequestStateTracker.setSyncRequestState(SyncRequestState.IncrementalSyncError)
                 throw throwable
             }
             val nbRooms = syncResponse.rooms?.invite.orEmpty().size + syncResponse.rooms?.join.orEmpty().size + syncResponse.rooms?.leave.orEmpty().size
@@ -177,8 +175,8 @@ internal class DefaultSyncTask @Inject constructor(
             Timber.tag(loggerTag.value).d(
                     "Incremental sync request parsing, $nbRooms room(s) $nbToDevice toDevice(s). Got nextBatch: $nextBatch"
             )
-            defaultSyncStatusService.setStatus(
-                    SyncStatusService.Status.IncrementalSyncParsing(
+            syncRequestStateTracker.setSyncRequestState(
+                    SyncRequestState.IncrementalSyncParsing(
                             rooms = nbRooms,
                             toDevice = nbToDevice
                     )
@@ -186,7 +184,7 @@ internal class DefaultSyncTask @Inject constructor(
             syncResponseHandler.handleResponse(syncResponse, token, null)
             syncResponseToReturn = syncResponse
             Timber.tag(loggerTag.value).d("Incremental sync done")
-            defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncDone)
+            syncRequestStateTracker.setSyncRequestState(SyncRequestState.IncrementalSyncDone)
         }
         syncStatisticsData.treatmentSyncTime = SystemClock.elapsedRealtime()
         syncStatisticsData.nbOfRooms = syncResponseToReturn?.rooms?.join?.size ?: 0
@@ -201,20 +199,20 @@ internal class DefaultSyncTask @Inject constructor(
         val status = initialSyncStatusRepository.getStep()
         if (workingFile.exists() && status >= InitialSyncStatus.STEP_DOWNLOADED) {
             Timber.tag(loggerTag.value).d("INIT_SYNC file is already here")
-            reportSubtask(defaultSyncStatusService, InitSyncStep.Downloading, 1, 0.3f) {
+            reportSubtask(syncRequestStateTracker, InitialSyncStep.Downloading, 1, 0.3f) {
                 // Empty task
             }
         } else {
             initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_DOWNLOADING)
             val syncResponse = logDuration("INIT_SYNC Perform server request", loggerTag, clock) {
-                reportSubtask(defaultSyncStatusService, InitSyncStep.ServerComputing, 1, 0.2f) {
+                reportSubtask(syncRequestStateTracker, InitialSyncStep.ServerComputing, 1, 0.2f) {
                     getSyncResponse(requestParams, MAX_NUMBER_OF_RETRY_AFTER_TIMEOUT)
                 }
             }
             syncStatisticsData.requestInitSyncTime = SystemClock.elapsedRealtime()
             if (syncResponse.isSuccessful) {
                 logDuration("INIT_SYNC Download and save to file", loggerTag, clock) {
-                    reportSubtask(defaultSyncStatusService, InitSyncStep.Downloading, 1, 0.1f) {
+                    reportSubtask(syncRequestStateTracker, InitialSyncStep.Downloading, 1, 0.1f) {
                         syncResponse.body()?.byteStream()?.use { inputStream ->
                             workingFile.outputStream().use { outputStream ->
                                 inputStream.copyTo(outputStream)
@@ -263,7 +261,7 @@ internal class DefaultSyncTask @Inject constructor(
             Timber.tag(loggerTag.value).d("INIT_SYNC $nbOfJoinedRooms rooms, $nbOfJoinedRoomsInFile ephemeral stored into files")
 
             logDuration("INIT_SYNC Database insertion", loggerTag, clock) {
-                syncResponseHandler.handleResponse(syncResponse, null, defaultSyncStatusService)
+                syncResponseHandler.handleResponse(syncResponse, null, syncRequestStateTracker)
             }
             initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_SUCCESS)
             syncResponse
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/sync/TaskInfo.kt
similarity index 81%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/TaskInfo.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/TaskInfo.kt
index fef16bf1d773492b7054901a4101c41434bc7482..7032aae2b2021e8c36e6d7eecfea0b217ce685ec 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/sync/TaskInfo.kt
@@ -14,15 +14,17 @@
  * limitations under the License.
  */
 
-package org.matrix.android.sdk.internal.session.initsync
+package org.matrix.android.sdk.internal.session.sync
 
-import org.matrix.android.sdk.api.session.initsync.InitSyncStep
+import org.matrix.android.sdk.api.session.sync.InitialSyncStep
 import timber.log.Timber
 
-internal class TaskInfo(val initSyncStep: InitSyncStep,
-                        val totalProgress: Int,
-                        val parent: TaskInfo?,
-                        val parentWeight: Float) {
+internal class TaskInfo(
+        val initialSyncStep: InitialSyncStep,
+        val totalProgress: Int,
+        val parent: TaskInfo?,
+        val parentWeight: Float
+) {
     var child: TaskInfo? = null
     var currentProgress = 0F
         private set
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 dd9576216649bac3d7129c941e64646b05b4d12c..b6142b3a7aef7192deb59982d3f1f67fa90d5e88 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
@@ -29,14 +29,16 @@ import org.matrix.android.sdk.api.session.sync.model.SyncResponse
 import org.matrix.android.sdk.api.session.sync.model.ToDeviceSyncResponse
 import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
 import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationService
-import org.matrix.android.sdk.internal.session.initsync.ProgressReporter
+import org.matrix.android.sdk.internal.session.sync.ProgressReporter
 import timber.log.Timber
 import javax.inject.Inject
 
 private val loggerTag = LoggerTag("CryptoSyncHandler", LoggerTag.CRYPTO)
 
-internal class CryptoSyncHandler @Inject constructor(private val cryptoService: DefaultCryptoService,
-                                                     private val verificationService: DefaultVerificationService) {
+internal class CryptoSyncHandler @Inject constructor(
+        private val cryptoService: DefaultCryptoService,
+        private val verificationService: DefaultVerificationService
+) {
 
     suspend fun handleToDevice(toDevice: ToDeviceSyncResponse, progressReporter: ProgressReporter? = null) {
         val total = toDevice.events?.size ?: 0
@@ -62,7 +64,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
     /**
      * Decrypt an encrypted event.
      *
-     * @param event      the event to decrypt
+     * @param event the event to decrypt
      * @param timelineId the timeline identifier
      * @return true if the event has been decrypted
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/GroupSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/GroupSyncHandler.kt
index 552462e25e69e451edd1533a8451db14a5897701..1983d9f433576e1ff5bd124e33b2a0b54c0de460 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/GroupSyncHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/GroupSyncHandler.kt
@@ -17,16 +17,16 @@
 package org.matrix.android.sdk.internal.session.sync.handler
 
 import io.realm.Realm
-import org.matrix.android.sdk.api.session.initsync.InitSyncStep
 import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.sync.InitialSyncStep
 import org.matrix.android.sdk.api.session.sync.model.GroupsSyncResponse
 import org.matrix.android.sdk.api.session.sync.model.InvitedGroupSync
 import org.matrix.android.sdk.internal.database.model.GroupEntity
 import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity
 import org.matrix.android.sdk.internal.database.query.getOrCreate
 import org.matrix.android.sdk.internal.database.query.where
-import org.matrix.android.sdk.internal.session.initsync.ProgressReporter
-import org.matrix.android.sdk.internal.session.initsync.mapWithProgress
+import org.matrix.android.sdk.internal.session.sync.ProgressReporter
+import org.matrix.android.sdk.internal.session.sync.mapWithProgress
 import javax.inject.Inject
 
 internal class GroupSyncHandler @Inject constructor() {
@@ -37,9 +37,11 @@ internal class GroupSyncHandler @Inject constructor() {
         data class LEFT(val data: Map<String, Any>) : HandlingStrategy()
     }
 
-    fun handle(realm: Realm,
-               roomsSyncResponse: GroupsSyncResponse,
-               reporter: ProgressReporter? = null) {
+    fun handle(
+            realm: Realm,
+            roomsSyncResponse: GroupsSyncResponse,
+            reporter: ProgressReporter? = null
+    ) {
         handleGroupSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), reporter)
         handleGroupSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), reporter)
         handleGroupSync(realm, HandlingStrategy.LEFT(roomsSyncResponse.leave), reporter)
@@ -49,26 +51,28 @@ internal class GroupSyncHandler @Inject constructor() {
 
     private fun handleGroupSync(realm: Realm, handlingStrategy: HandlingStrategy, reporter: ProgressReporter?) {
         val groups = when (handlingStrategy) {
-            is HandlingStrategy.JOINED  ->
-                handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountGroups, 0.6f) {
+            is HandlingStrategy.JOINED ->
+                handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountGroups, 0.6f) {
                     handleJoinedGroup(realm, it.key)
                 }
 
             is HandlingStrategy.INVITED ->
-                handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountGroups, 0.3f) {
+                handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountGroups, 0.3f) {
                     handleInvitedGroup(realm, it.key)
                 }
 
-            is HandlingStrategy.LEFT    ->
-                handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountGroups, 0.1f) {
+            is HandlingStrategy.LEFT ->
+                handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountGroups, 0.1f) {
                     handleLeftGroup(realm, it.key)
                 }
         }
         realm.insertOrUpdate(groups)
     }
 
-    private fun handleJoinedGroup(realm: Realm,
-                                  groupId: String): GroupEntity {
+    private fun handleJoinedGroup(
+            realm: Realm,
+            groupId: String
+    ): GroupEntity {
         val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId)
         val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupId)
         groupEntity.membership = Membership.JOIN
@@ -76,8 +80,10 @@ internal class GroupSyncHandler @Inject constructor() {
         return groupEntity
     }
 
-    private fun handleInvitedGroup(realm: Realm,
-                                   groupId: String): GroupEntity {
+    private fun handleInvitedGroup(
+            realm: Realm,
+            groupId: String
+    ): GroupEntity {
         val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId)
         val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupId)
         groupEntity.membership = Membership.INVITE
@@ -85,8 +91,10 @@ internal class GroupSyncHandler @Inject constructor() {
         return groupEntity
     }
 
-    private fun handleLeftGroup(realm: Realm,
-                                groupId: String): GroupEntity {
+    private fun handleLeftGroup(
+            realm: Realm,
+            groupId: String
+    ): GroupEntity {
         val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId)
         val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupId)
         groupEntity.membership = Membership.LEAVE
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt
index c213ea4bcfdbac5a68f5b19ab46e4b98cc4513c9..0f296ded5d31173a6e92ff629674c29db53c1765 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt
@@ -84,10 +84,10 @@ internal class UserAccountDataSyncHandler @Inject constructor(
             // Generic handling, just save in base
             handleGenericAccountData(realm, event.type, event.content)
             when (event.type) {
-                UserAccountDataTypes.TYPE_DIRECT_MESSAGES   -> handleDirectChatRooms(realm, event)
-                UserAccountDataTypes.TYPE_PUSH_RULES        -> handlePushRules(realm, event)
+                UserAccountDataTypes.TYPE_DIRECT_MESSAGES -> handleDirectChatRooms(realm, event)
+                UserAccountDataTypes.TYPE_PUSH_RULES -> handlePushRules(realm, event)
                 UserAccountDataTypes.TYPE_IGNORED_USER_LIST -> handleIgnoredUsers(realm, event)
-                UserAccountDataTypes.TYPE_BREADCRUMBS       -> handleBreadcrumbs(realm, event)
+                UserAccountDataTypes.TYPE_BREADCRUMBS -> handleBreadcrumbs(realm, event)
             }
         }
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ReadReceiptHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ReadReceiptHandler.kt
index 77bee18df932814a3bab3fbbcdf2f11712cf90dc..7329611a01776e50577334842457a40bff73ded7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ReadReceiptHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ReadReceiptHandler.kt
@@ -44,9 +44,11 @@ internal class ReadReceiptHandler @Inject constructor(
 
     companion object {
 
-        fun createContent(userId: String,
-                          eventId: String,
-                          currentTimeMillis: Long): ReadReceiptContent {
+        fun createContent(
+                userId: String,
+                eventId: String,
+                currentTimeMillis: Long
+        ): ReadReceiptContent {
             return mapOf(
                     eventId to mapOf(
                             READ_KEY to mapOf(
@@ -59,11 +61,13 @@ internal class ReadReceiptHandler @Inject constructor(
         }
     }
 
-    fun handle(realm: Realm,
-               roomId: String,
-               content: ReadReceiptContent?,
-               isInitialSync: Boolean,
-               aggregator: SyncResponsePostTreatmentAggregator?) {
+    fun handle(
+            realm: Realm,
+            roomId: String,
+            content: ReadReceiptContent?,
+            isInitialSync: Boolean,
+            aggregator: SyncResponsePostTreatmentAggregator?
+    ) {
         content ?: return
 
         try {
@@ -73,11 +77,13 @@ internal class ReadReceiptHandler @Inject constructor(
         }
     }
 
-    private fun handleReadReceiptContent(realm: Realm,
-                                         roomId: String,
-                                         content: ReadReceiptContent,
-                                         isInitialSync: Boolean,
-                                         aggregator: SyncResponsePostTreatmentAggregator?) {
+    private fun handleReadReceiptContent(
+            realm: Realm,
+            roomId: String,
+            content: ReadReceiptContent,
+            isInitialSync: Boolean,
+            aggregator: SyncResponsePostTreatmentAggregator?
+    ) {
         if (isInitialSync) {
             initialSyncStrategy(realm, roomId, content)
         } else {
@@ -101,10 +107,12 @@ internal class ReadReceiptHandler @Inject constructor(
         realm.insertOrUpdate(readReceiptSummaries)
     }
 
-    private fun incrementalSyncStrategy(realm: Realm,
-                                        roomId: String,
-                                        content: ReadReceiptContent,
-                                        aggregator: SyncResponsePostTreatmentAggregator?) {
+    private fun incrementalSyncStrategy(
+            realm: Realm,
+            roomId: String,
+            content: ReadReceiptContent,
+            aggregator: SyncResponsePostTreatmentAggregator?
+    ) {
         // First check if we have data from init sync to handle
         getContentFromInitSync(roomId)?.let {
             Timber.w("INIT_SYNC Insert during incremental sync RR for room $roomId")
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 c5d14afac0096ac9afb401b81f2a7e8ca172ead0..f99fe964102fa06a7ad9bacc93f9d1625e68af3f 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
@@ -27,11 +27,11 @@ 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.session.homeserver.HomeServerCapabilitiesService
-import org.matrix.android.sdk.api.session.initsync.InitSyncStep
 import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
 import org.matrix.android.sdk.api.session.room.send.SendState
 import org.matrix.android.sdk.api.session.room.threads.model.ThreadSummaryUpdateType
+import org.matrix.android.sdk.api.session.sync.InitialSyncStep
 import org.matrix.android.sdk.api.session.sync.InitialSyncStrategy
 import org.matrix.android.sdk.api.session.sync.initialSyncStrategy
 import org.matrix.android.sdk.api.session.sync.model.InvitedRoomSync
@@ -57,6 +57,7 @@ import org.matrix.android.sdk.internal.database.model.deleteOnCascade
 import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity
 import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
 import org.matrix.android.sdk.internal.database.query.find
+import org.matrix.android.sdk.internal.database.query.findAll
 import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom
 import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfThread
 import org.matrix.android.sdk.internal.database.query.getOrCreate
@@ -67,17 +68,17 @@ import org.matrix.android.sdk.internal.di.UserId
 import org.matrix.android.sdk.internal.extensions.clearWith
 import org.matrix.android.sdk.internal.session.StreamEventsManager
 import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent
-import org.matrix.android.sdk.internal.session.initsync.ProgressReporter
-import org.matrix.android.sdk.internal.session.initsync.mapWithProgress
-import org.matrix.android.sdk.internal.session.initsync.reportSubtask
 import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembershipStateDataSource
 import org.matrix.android.sdk.internal.session.room.membership.RoomMemberEventHandler
 import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater
 import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
 import org.matrix.android.sdk.internal.session.room.timeline.TimelineInput
 import org.matrix.android.sdk.internal.session.room.typing.TypingEventContent
+import org.matrix.android.sdk.internal.session.sync.ProgressReporter
 import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator
+import org.matrix.android.sdk.internal.session.sync.mapWithProgress
 import org.matrix.android.sdk.internal.session.sync.parsing.RoomSyncAccountDataHandler
+import org.matrix.android.sdk.internal.session.sync.reportSubtask
 import org.matrix.android.sdk.internal.util.computeBestChunkSize
 import org.matrix.android.sdk.internal.util.time.Clock
 import timber.log.Timber
@@ -106,11 +107,13 @@ internal class RoomSyncHandler @Inject constructor(
         data class LEFT(val data: Map<String, RoomSync>) : HandlingStrategy()
     }
 
-    fun handle(realm: Realm,
-               roomsSyncResponse: RoomsSyncResponse,
-               isInitialSync: Boolean,
-               aggregator: SyncResponsePostTreatmentAggregator,
-               reporter: ProgressReporter? = null) {
+    fun handle(
+            realm: Realm,
+            roomsSyncResponse: RoomsSyncResponse,
+            isInitialSync: Boolean,
+            aggregator: SyncResponsePostTreatmentAggregator,
+            reporter: ProgressReporter? = null
+    ) {
         handleRoomSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), isInitialSync, aggregator, reporter)
         handleRoomSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), isInitialSync, aggregator, reporter)
         handleRoomSync(realm, HandlingStrategy.LEFT(roomsSyncResponse.leave), isInitialSync, aggregator, reporter)
@@ -124,11 +127,13 @@ internal class RoomSyncHandler @Inject constructor(
     }
     // PRIVATE METHODS *****************************************************************************
 
-    private fun handleRoomSync(realm: Realm,
-                               handlingStrategy: HandlingStrategy,
-                               isInitialSync: Boolean,
-                               aggregator: SyncResponsePostTreatmentAggregator,
-                               reporter: ProgressReporter?) {
+    private fun handleRoomSync(
+            realm: Realm,
+            handlingStrategy: HandlingStrategy,
+            isInitialSync: Boolean,
+            aggregator: SyncResponsePostTreatmentAggregator,
+            reporter: ProgressReporter?
+    ) {
         val insertType = if (isInitialSync) {
             EventInsertType.INITIAL_SYNC
         } else {
@@ -136,24 +141,24 @@ internal class RoomSyncHandler @Inject constructor(
         }
         val syncLocalTimeStampMillis = clock.epochMillis()
         val rooms = when (handlingStrategy) {
-            is HandlingStrategy.JOINED  -> {
+            is HandlingStrategy.JOINED -> {
                 if (isInitialSync && initialSyncStrategy is InitialSyncStrategy.Optimized) {
                     insertJoinRoomsFromInitSync(realm, handlingStrategy, syncLocalTimeStampMillis, aggregator, reporter)
                     // Rooms are already inserted, return an empty list
                     emptyList()
                 } else {
-                    handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountJoinedRooms, 0.6f) {
+                    handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountJoinedRooms, 0.6f) {
                         handleJoinedRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis, aggregator)
                     }
                 }
             }
             is HandlingStrategy.INVITED ->
-                handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountInvitedRooms, 0.1f) {
+                handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountInvitedRooms, 0.1f) {
                     handleInvitedRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis)
                 }
 
-            is HandlingStrategy.LEFT    -> {
-                handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountLeftRooms, 0.3f) {
+            is HandlingStrategy.LEFT -> {
+                handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountLeftRooms, 0.3f) {
                     handleLeftRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis)
                 }
             }
@@ -161,18 +166,20 @@ internal class RoomSyncHandler @Inject constructor(
         realm.insertOrUpdate(rooms)
     }
 
-    private fun insertJoinRoomsFromInitSync(realm: Realm,
-                                            handlingStrategy: HandlingStrategy.JOINED,
-                                            syncLocalTimeStampMillis: Long,
-                                            aggregator: SyncResponsePostTreatmentAggregator,
-                                            reporter: ProgressReporter?) {
+    private fun insertJoinRoomsFromInitSync(
+            realm: Realm,
+            handlingStrategy: HandlingStrategy.JOINED,
+            syncLocalTimeStampMillis: Long,
+            aggregator: SyncResponsePostTreatmentAggregator,
+            reporter: ProgressReporter?
+    ) {
         val bestChunkSize = computeBestChunkSize(
                 listSize = handlingStrategy.data.keys.size,
                 limit = (initialSyncStrategy as? InitialSyncStrategy.Optimized)?.maxRoomsToInsert ?: Int.MAX_VALUE
         )
 
         if (bestChunkSize.shouldChunk()) {
-            reportSubtask(reporter, InitSyncStep.ImportingAccountJoinedRooms, bestChunkSize.numberOfChunks, 0.6f) {
+            reportSubtask(reporter, InitialSyncStep.ImportingAccountJoinedRooms, bestChunkSize.numberOfChunks, 0.6f) {
                 Timber.d("INIT_SYNC ${handlingStrategy.data.keys.size} rooms to insert, split with $bestChunkSize")
                 // I cannot find a better way to chunk a map, so chunk the keys and then create new maps
                 handlingStrategy.data.keys
@@ -196,19 +203,21 @@ internal class RoomSyncHandler @Inject constructor(
             }
         } else {
             // No need to split
-            val rooms = handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountJoinedRooms, 0.6f) {
+            val rooms = handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountJoinedRooms, 0.6f) {
                 handleJoinedRoom(realm, it.key, it.value, EventInsertType.INITIAL_SYNC, syncLocalTimeStampMillis, aggregator)
             }
             realm.insertOrUpdate(rooms)
         }
     }
 
-    private fun handleJoinedRoom(realm: Realm,
-                                 roomId: String,
-                                 roomSync: RoomSync,
-                                 insertType: EventInsertType,
-                                 syncLocalTimestampMillis: Long,
-                                 aggregator: SyncResponsePostTreatmentAggregator): RoomEntity {
+    private fun handleJoinedRoom(
+            realm: Realm,
+            roomId: String,
+            roomSync: RoomSync,
+            insertType: EventInsertType,
+            syncLocalTimestampMillis: Long,
+            aggregator: SyncResponsePostTreatmentAggregator
+    ): RoomEntity {
         Timber.v("Handle join sync for room $roomId")
         val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
 
@@ -281,11 +290,13 @@ internal class RoomSyncHandler @Inject constructor(
         return roomEntity
     }
 
-    private fun handleInvitedRoom(realm: Realm,
-                                  roomId: String,
-                                  roomSync: InvitedRoomSync,
-                                  insertType: EventInsertType,
-                                  syncLocalTimestampMillis: Long): RoomEntity {
+    private fun handleInvitedRoom(
+            realm: Realm,
+            roomId: String,
+            roomSync: InvitedRoomSync,
+            insertType: EventInsertType,
+            syncLocalTimestampMillis: Long
+    ): RoomEntity {
         Timber.v("Handle invited sync for room $roomId")
         val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
         val roomEntity = RoomEntity.getOrCreate(realm, roomId)
@@ -312,11 +323,13 @@ internal class RoomSyncHandler @Inject constructor(
         return roomEntity
     }
 
-    private fun handleLeftRoom(realm: Realm,
-                               roomId: String,
-                               roomSync: RoomSync,
-                               insertType: EventInsertType,
-                               syncLocalTimestampMillis: Long): RoomEntity {
+    private fun handleLeftRoom(
+            realm: Realm,
+            roomId: String,
+            roomSync: RoomSync,
+            insertType: EventInsertType,
+            syncLocalTimestampMillis: Long
+    ): RoomEntity {
         val isInitialSync = insertType == EventInsertType.INITIAL_SYNC
         val roomEntity = RoomEntity.getOrCreate(realm, roomId)
         for (event in roomSync.state?.events.orEmpty()) {
@@ -357,22 +370,25 @@ internal class RoomSyncHandler @Inject constructor(
         return roomEntity
     }
 
-    private fun handleTimelineEvents(realm: Realm,
-                                     roomId: String,
-                                     roomEntity: RoomEntity,
-                                     eventList: List<Event>,
-                                     prevToken: String? = null,
-                                     isLimited: Boolean = true,
-                                     insertType: EventInsertType,
-                                     syncLocalTimestampMillis: Long,
-                                     aggregator: SyncResponsePostTreatmentAggregator): ChunkEntity {
+    private fun handleTimelineEvents(
+            realm: Realm,
+            roomId: String,
+            roomEntity: RoomEntity,
+            eventList: List<Event>,
+            prevToken: String? = null,
+            isLimited: Boolean = true,
+            insertType: EventInsertType,
+            syncLocalTimestampMillis: Long,
+            aggregator: SyncResponsePostTreatmentAggregator
+    ): ChunkEntity {
         val lastChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomEntity.roomId)
-        if (isLimited && lastChunk != null) {
-            lastChunk.deleteOnCascade(deleteStateEvents = false, canDeleteRoot = true)
-        }
         val chunkEntity = if (!isLimited && lastChunk != null) {
             lastChunk
         } else {
+            // Delete all chunks of the room in case of gap.
+            ChunkEntity.findAll(realm, roomId).forEach {
+                it.deleteOnCascade(deleteStateEvents = false, canDeleteRoot = true)
+            }
             realm.createObject<ChunkEntity>().apply {
                 this.prevToken = prevToken
                 this.isLastForward = true
@@ -500,11 +516,13 @@ internal class RoomSyncHandler @Inject constructor(
      * Adds new event to the appropriate thread chunk. If the event is already in
      * the thread timeline and /relations api, we should not added it
      */
-    private fun addToThreadChunkIfNeeded(realm: Realm,
-                                         roomId: String,
-                                         threadId: String,
-                                         timelineEventEntity: TimelineEventEntity?,
-                                         roomEntity: RoomEntity) {
+    private fun addToThreadChunkIfNeeded(
+            realm: Realm,
+            roomId: String,
+            threadId: String,
+            timelineEventEntity: TimelineEventEntity?,
+            roomEntity: RoomEntity
+    ) {
         val eventId = timelineEventEntity?.eventId ?: return
 
         ChunkEntity.findLastForwardChunkOfThread(realm, roomId, threadId)?.let { threadChunk ->
@@ -520,9 +538,10 @@ internal class RoomSyncHandler @Inject constructor(
 
     private fun decryptIfNeeded(event: Event, roomId: String) {
         try {
+            val timelineId = generateTimelineId(roomId)
             // Event from sync does not have roomId, so add it to the event first
             // note: runBlocking should be used here while we are in realm single thread executor, to avoid thread switching
-            val result = runBlocking { cryptoService.decryptEvent(event.copy(roomId = roomId), "") }
+            val result = runBlocking { cryptoService.decryptEvent(event.copy(roomId = roomId), timelineId) }
             event.mxDecryptionResult = OlmDecryptionResult(
                     payload = result.clearEvent,
                     senderKey = result.senderCurve25519Key,
@@ -537,15 +556,21 @@ internal class RoomSyncHandler @Inject constructor(
         }
     }
 
+    private fun generateTimelineId(roomId: String): String {
+        return "RoomSyncHandler$roomId"
+    }
+
     data class EphemeralResult(
             val typingUserIds: List<String> = emptyList()
     )
 
-    private fun handleEphemeral(realm: Realm,
-                                roomId: String,
-                                ephemeralEvents: List<Event>,
-                                isInitialSync: Boolean,
-                                aggregator: SyncResponsePostTreatmentAggregator): EphemeralResult {
+    private fun handleEphemeral(
+            realm: Realm,
+            roomId: String,
+            ephemeralEvents: List<Event>,
+            isInitialSync: Boolean,
+            aggregator: SyncResponsePostTreatmentAggregator
+    ): EphemeralResult {
         var result = EphemeralResult()
         for (event in ephemeralEvents) {
             when (event.type) {
@@ -555,12 +580,12 @@ internal class RoomSyncHandler @Inject constructor(
                         readReceiptHandler.handle(realm, roomId, readReceiptContent, isInitialSync, aggregator)
                     }
                 }
-                EventType.TYPING  -> {
+                EventType.TYPING -> {
                     event.content.toModel<TypingEventContent>()?.let { typingEventContent ->
                         result = result.copy(typingUserIds = typingEventContent.typingUserIds)
                     }
                 }
-                else              -> Timber.w("Ephemeral event type '${event.type}' not yet supported")
+                else -> Timber.w("Ephemeral event type '${event.type}' not yet supported")
             }
         }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomTypingUsersHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomTypingUsersHandler.kt
index 63db13a5b804871163c24174c532bc3fdbfac4e4..54bb63753c9cacb5d4ada425bf993cd3095288ca 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomTypingUsersHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomTypingUsersHandler.kt
@@ -23,8 +23,10 @@ import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
 import org.matrix.android.sdk.internal.session.typing.DefaultTypingUsersTracker
 import javax.inject.Inject
 
-internal class RoomTypingUsersHandler @Inject constructor(@UserId private val userId: String,
-                                                          private val typingUsersTracker: DefaultTypingUsersTracker) {
+internal class RoomTypingUsersHandler @Inject constructor(
+        @UserId private val userId: String,
+        private val typingUsersTracker: DefaultTypingUsersTracker
+) {
 
     // TODO This could be handled outside of the Realm transaction. Use the new aggregator?
     fun handle(realm: Realm, roomId: String, ephemeralResult: RoomSyncHandler.EphemeralResult?) {
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 03e076c217726f29c2d0ebffb36b04b55a9c3349..8c7557a5b8611f156d8f970457fc0c2e79ea584f 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
@@ -156,10 +156,12 @@ internal class ThreadsAwarenessHandler @Inject constructor(
      * Handle events mainly coming from the RoomSyncHandler.
      * @return The content to inject in the roomSyncHandler live events
      */
-    fun makeEventThreadAware(realm: Realm,
-                             roomId: String?,
-                             event: Event?,
-                             eventEntity: EventEntity? = null): String? {
+    fun makeEventThreadAware(
+            realm: Realm,
+            roomId: String?,
+            event: Event?,
+            eventEntity: EventEntity? = null
+    ): String? {
         event ?: return null
         roomId ?: return null
         if (lightweightSettingsStorage.areThreadMessagesEnabled() && !isReplyEvent(event)) return null
@@ -206,6 +208,8 @@ internal class ThreadsAwarenessHandler @Inject constructor(
     /**
      * Handle for not thread events that we have marked them as root.
      * Find relations and inject them accordingly
+     * @param realm the realm instance
+     * @param roomId the current room Id
      * @param eventEntity the current eventEntity received
      * @param event the current event received
      * @return The content to inject in the roomSyncHandler live events
@@ -229,9 +233,12 @@ internal class ThreadsAwarenessHandler @Inject constructor(
      * 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.
+     * @param realm the realm instance
+     * @param roomId the current room Id
      * @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
+     * @param threadRelation the information about thread
      * @return The content to inject in the roomSyncHandler live events
      */
     private fun handleEventsThatRelatesTo(
@@ -266,10 +273,12 @@ internal class ThreadsAwarenessHandler @Inject constructor(
      * Actual update the eventEntity with the new payload.
      * @return the content to inject when this is executed by RoomSyncHandler
      */
-    private fun updateEventEntity(event: Event,
-                                  eventEntity: EventEntity?,
-                                  eventPayload: MutableMap<String, Any>,
-                                  messageTextContent: Content): String? {
+    private fun updateEventEntity(
+            event: Event,
+            eventEntity: EventEntity?,
+            eventPayload: MutableMap<String, Any>,
+            messageTextContent: Content
+    ): String? {
         eventPayload["content"] = messageTextContent
 
         if (event.isEncrypted()) {
@@ -291,16 +300,20 @@ internal class ThreadsAwarenessHandler @Inject constructor(
     }
 
     /**
-     * Injecting $eventToInject decrypted content as a reply to $event.
-     * @param eventToInject the event that will inject
+     * Injecting [eventToInject] decrypted content as a reply to event.
+     * @param roomId the room id
      * @param eventBody the actual event body
+     * @param eventToInject the event that will inject
+     * @param eventToInjectBody the event body to inject
+     * @param threadRelation the information about thread
      * @return The final content with the injected event
      */
-    private fun injectEvent(roomId: String,
-                            eventBody: String,
-                            eventToInject: Event,
-                            eventToInjectBody: String,
-                            threadRelation: RelationDefaultContent?
+    private fun injectEvent(
+            roomId: String,
+            eventBody: String,
+            eventToInject: Event,
+            eventToInjectBody: String,
+            threadRelation: RelationDefaultContent?
     ): Content? {
         val eventToInjectId = eventToInject.eventId ?: return null
         val eventIdToInjectSenderId = eventToInject.senderId.orEmpty()
@@ -326,11 +339,13 @@ internal class ThreadsAwarenessHandler @Inject constructor(
     /**
      * Integrate fallback Quote reply.
      */
-    private fun injectFallbackIndicator(event: Event,
-                                        eventBody: String,
-                                        eventEntity: EventEntity?,
-                                        eventPayload: MutableMap<String, Any>,
-                                        threadRelation: RelationDefaultContent?): String? {
+    private fun injectFallbackIndicator(
+            event: Event,
+            eventBody: String,
+            eventEntity: EventEntity?,
+            eventPayload: MutableMap<String, Any>,
+            threadRelation: RelationDefaultContent?
+    ): String? {
         val replyFormatted = LocalEchoEventFactory.QUOTE_PATTERN.format(
                 "In reply to a thread",
                 eventBody
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt
index fc6a4e03d6410fb49e2884fef42a3459a70e791d..24a60a80da6ae50059dd3d619a2922b6db3c67fc 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt
@@ -56,11 +56,12 @@ private const val DEFAULT_LONG_POOL_TIMEOUT = 30_000L
 
 private val loggerTag = LoggerTag("SyncThread", LoggerTag.SYNC)
 
-internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
-                                              private val networkConnectivityChecker: NetworkConnectivityChecker,
-                                              private val backgroundDetectionObserver: BackgroundDetectionObserver,
-                                              private val activeCallHandler: ActiveCallHandler,
-                                              private val lightweightSettingsStorage: DefaultLightweightSettingsStorage
+internal class SyncThread @Inject constructor(
+        private val syncTask: SyncTask,
+        private val networkConnectivityChecker: NetworkConnectivityChecker,
+        private val backgroundDetectionObserver: BackgroundDetectionObserver,
+        private val activeCallHandler: ActiveCallHandler,
+        private val lightweightSettingsStorage: DefaultLightweightSettingsStorage
 ) : Thread("SyncThread"), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener {
 
     private var state: SyncState = SyncState.Idle
@@ -179,8 +180,8 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
                 val afterPause = state.let { it is SyncState.Running && it.afterPause }
                 val timeout = when {
                     previousSyncResponseHasToDevice -> 0L /* Force timeout to 0 */
-                    afterPause                      -> 0L /* No timeout after a pause */
-                    else                            -> DEFAULT_LONG_POOL_TIMEOUT
+                    afterPause -> 0L /* No timeout after a pause */
+                    else -> DEFAULT_LONG_POOL_TIMEOUT
                 }
                 Timber.tag(loggerTag.value).d("Execute sync request with timeout $timeout")
                 val presence = lightweightSettingsStorage.getSyncPresenceStatus()
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 bbb18b664c6bf43a72b9024c7f593a243800cad4..0cc7944d58c02eba1f173932d0254eb34cca9697 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
@@ -119,9 +119,11 @@ internal class SyncWorker(context: Context, workerParameters: WorkerParameters,
     companion object {
         private const val BG_SYNC_WORK_NAME = "BG_SYNCP"
 
-        fun requireBackgroundSync(workManagerProvider: WorkManagerProvider,
-                                  sessionId: String,
-                                  serverTimeoutInSeconds: Long = 0) {
+        fun requireBackgroundSync(
+                workManagerProvider: WorkManagerProvider,
+                sessionId: String,
+                serverTimeoutInSeconds: Long = 0
+        ) {
             val data = WorkerParamsFactory.toData(
                     Params(
                             sessionId = sessionId,
@@ -139,11 +141,13 @@ internal class SyncWorker(context: Context, workerParameters: WorkerParameters,
                     .enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest)
         }
 
-        fun automaticallyBackgroundSync(workManagerProvider: WorkManagerProvider,
-                                        sessionId: String,
-                                        serverTimeoutInSeconds: Long = 0,
-                                        delayInSeconds: Long = 30,
-                                        forceImmediate: Boolean = false) {
+        fun automaticallyBackgroundSync(
+                workManagerProvider: WorkManagerProvider,
+                sessionId: String,
+                serverTimeoutInSeconds: Long = 0,
+                delayInSeconds: Long = 30,
+                forceImmediate: Boolean = false
+        ) {
             val data = WorkerParamsFactory.toData(
                     Params(
                             sessionId = sessionId,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/TokensChunkResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/TokensChunkResponse.kt
index 533ba70b054afa40b9e315bfef300ec2dc292115..40fdcbbb84c1732ece74cf5cc5342d57d7b28809 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/TokensChunkResponse.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/TokensChunkResponse.kt
@@ -22,4 +22,5 @@ import com.squareup.moshi.JsonClass
 internal data class TokensChunkResponse<T>(
         val start: String? = null,
         val end: String? = null,
-        val chunk: List<T>? = null)
+        val chunk: List<T>? = null
+)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/parsing/RoomSyncAccountDataHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/parsing/RoomSyncAccountDataHandler.kt
index 5e7bde87e77d2a668e1e9369331debe9ef283206..b1b2bfef339495fea94a6feff635322ba219a7eb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/parsing/RoomSyncAccountDataHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/parsing/RoomSyncAccountDataHandler.kt
@@ -32,8 +32,10 @@ import org.matrix.android.sdk.internal.session.sync.handler.room.RoomFullyReadHa
 import org.matrix.android.sdk.internal.session.sync.handler.room.RoomTagHandler
 import javax.inject.Inject
 
-internal class RoomSyncAccountDataHandler @Inject constructor(private val roomTagHandler: RoomTagHandler,
-                                                              private val roomFullyReadHandler: RoomFullyReadHandler) {
+internal class RoomSyncAccountDataHandler @Inject constructor(
+        private val roomTagHandler: RoomTagHandler,
+        private val roomFullyReadHandler: RoomFullyReadHandler
+) {
 
     fun handle(realm: Realm, roomId: String, accountData: RoomSyncAccountData) {
         if (accountData.events.isNullOrEmpty()) {
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 9876643bed1a6c8ca3ff0c3ced398ef91183d11b..b687f5833af8300714b4ff92e873877d00105d96 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
@@ -51,8 +51,10 @@ internal class DefaultTermsService @Inject constructor(
         private val updateUserAccountDataTask: UpdateUserAccountDataTask
 ) : TermsService {
 
-    override suspend fun getTerms(serviceType: TermsService.ServiceType,
-                                  baseUrl: String): GetTermsResponse {
+    override suspend fun getTerms(
+            serviceType: TermsService.ServiceType,
+            baseUrl: String
+    ): GetTermsResponse {
         val url = buildUrl(baseUrl, serviceType)
         val termsResponse = executeRequest(null) {
             termsAPI.getTerms("${url}terms")
@@ -90,10 +92,12 @@ internal class DefaultTermsService @Inject constructor(
         }
     }
 
-    override suspend fun agreeToTerms(serviceType: TermsService.ServiceType,
-                                      baseUrl: String,
-                                      agreedUrls: List<String>,
-                                      token: String?) {
+    override suspend fun agreeToTerms(
+            serviceType: TermsService.ServiceType,
+            baseUrl: String,
+            agreedUrls: List<String>,
+            token: String?
+    ) {
         val url = buildUrl(baseUrl, serviceType)
         val tokenToUse = token?.takeIf { it.isNotEmpty() } ?: getToken(baseUrl)
 
@@ -128,7 +132,7 @@ internal class DefaultTermsService @Inject constructor(
     private fun buildUrl(baseUrl: String, serviceType: TermsService.ServiceType): String {
         val servicePath = when (serviceType) {
             TermsService.ServiceType.IntegrationManager -> NetworkConstants.URI_INTEGRATION_MANAGER_PATH
-            TermsService.ServiceType.IdentityService    -> NetworkConstants.URI_IDENTITY_PATH_V2
+            TermsService.ServiceType.IdentityService -> NetworkConstants.URI_IDENTITY_PATH_V2
         }
         return "${baseUrl.ensureTrailingSlash()}$servicePath"
     }
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 f6f57bf0ef0919b0c4fc4dfbc720d9186c6ccf80..6a3328ee52468c735634098cf5e2577e6fedee71 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
@@ -37,15 +37,19 @@ internal interface TermsAPI {
      * This request requires authentication.
      */
     @POST
-    suspend fun agreeToTerms(@Url url: String,
-                             @Body params: AcceptTermsBody,
-                             @Header(HttpHeaders.Authorization) token: String)
+    suspend fun agreeToTerms(
+            @Url url: String,
+            @Body params: AcceptTermsBody,
+            @Header(HttpHeaders.Authorization) token: String
+    )
 
     /**
      * 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).
      */
     @POST
-    suspend fun register(@Url url: String,
-                         @Body body: JsonDict = emptyJsonDict)
+    suspend fun register(
+            @Url url: String,
+            @Body body: JsonDict = emptyJsonDict
+    )
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsModule.kt
index d7b6f68add0399b87579444be5bb759f3a5118b7..06d12bfe76be9497de9f40e4e609d5e24170b096 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsModule.kt
@@ -34,8 +34,10 @@ internal abstract class TermsModule {
         @Provides
         @JvmStatic
         @SessionScope
-        fun providesTermsAPI(@UnauthenticatedWithCertificate unauthenticatedOkHttpClient: Lazy<OkHttpClient>,
-                             retrofitFactory: RetrofitFactory): TermsAPI {
+        fun providesTermsAPI(
+                @UnauthenticatedWithCertificate unauthenticatedOkHttpClient: Lazy<OkHttpClient>,
+                retrofitFactory: RetrofitFactory
+        ): TermsAPI {
             val retrofit = retrofitFactory.create(unauthenticatedOkHttpClient, "https://foo.bar")
             return retrofit.create(TermsAPI::class.java)
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/DefaultThirdPartyService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/DefaultThirdPartyService.kt
index 210cb192e7f7c3c832432041d87982c025548a93..c8b9eaf81065a8a073d66a6dcc86417e473f470f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/DefaultThirdPartyService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/DefaultThirdPartyService.kt
@@ -21,8 +21,10 @@ import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService
 import org.matrix.android.sdk.api.session.thirdparty.model.ThirdPartyUser
 import javax.inject.Inject
 
-internal class DefaultThirdPartyService @Inject constructor(private val getThirdPartyProtocolTask: GetThirdPartyProtocolsTask,
-                                                            private val getThirdPartyUserTask: GetThirdPartyUserTask) :
+internal class DefaultThirdPartyService @Inject constructor(
+        private val getThirdPartyProtocolTask: GetThirdPartyProtocolsTask,
+        private val getThirdPartyUserTask: GetThirdPartyUserTask
+) :
         ThirdPartyService {
 
     override suspend fun getThirdPartyProtocols(): Map<String, ThirdPartyProtocol> {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/ThirdPartyAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/ThirdPartyAPI.kt
index 3ecc39ac9484d0f371896b3f069e75292b7f64a7..6759205bf345babfeaecea4ed4056aac29fb26e9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/ThirdPartyAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/ThirdPartyAPI.kt
@@ -39,6 +39,8 @@ internal interface ThirdPartyAPI {
      * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-thirdparty-user-protocol
      */
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "thirdparty/user/{protocol}")
-    suspend fun getThirdPartyUser(@Path("protocol") protocol: String,
-                                  @QueryMap params: Map<String, String>?): List<ThirdPartyUser>
+    suspend fun getThirdPartyUser(
+            @Path("protocol") protocol: String,
+            @QueryMap params: Map<String, String>?
+    ): List<ThirdPartyUser>
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt
index 4ffc42e714ed1afa75d88832957f043c3090be5f..660cf118dff276cff2e71a04293b0c48d3343ed3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt
@@ -26,10 +26,12 @@ import org.matrix.android.sdk.internal.session.user.accountdata.UpdateIgnoredUse
 import org.matrix.android.sdk.internal.session.user.model.SearchUserTask
 import javax.inject.Inject
 
-internal class DefaultUserService @Inject constructor(private val userDataSource: UserDataSource,
-                                                      private val searchUserTask: SearchUserTask,
-                                                      private val updateIgnoredUserIdsTask: UpdateIgnoredUserIdsTask,
-                                                      private val getProfileInfoTask: GetProfileInfoTask) : UserService {
+internal class DefaultUserService @Inject constructor(
+        private val userDataSource: UserDataSource,
+        private val searchUserTask: SearchUserTask,
+        private val updateIgnoredUserIdsTask: UpdateIgnoredUserIdsTask,
+        private val getProfileInfoTask: GetProfileInfoTask
+) : UserService {
 
     override fun getUser(userId: String): User? {
         return userDataSource.getUser(userId)
@@ -59,9 +61,11 @@ internal class DefaultUserService @Inject constructor(private val userDataSource
         return userDataSource.getIgnoredUsersLive()
     }
 
-    override suspend fun searchUsersDirectory(search: String,
-                                              limit: Int,
-                                              excludedUserIds: Set<String>): List<User> {
+    override suspend fun searchUsersDirectory(
+            search: String,
+            limit: Int,
+            excludedUserIds: Set<String>
+    ): List<User> {
         val params = SearchUserTask.Params(limit, search, excludedUserIds)
         return searchUserTask.execute(params)
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt
index e83725b10da19b651ad59073fc9c46f4763c0ef7..f9feb04e97ae868fe4600cfd3e59311fcd786b28 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt
@@ -36,8 +36,10 @@ import org.matrix.android.sdk.internal.database.query.where
 import org.matrix.android.sdk.internal.di.SessionDatabase
 import javax.inject.Inject
 
-internal class UserDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
-                                                  private val realmSessionProvider: RealmSessionProvider) {
+internal class UserDataSource @Inject constructor(
+        @SessionDatabase private val monarchy: Monarchy,
+        private val realmSessionProvider: RealmSessionProvider
+) {
 
     private val realmDataSourceFactory: Monarchy.RealmDataSourceFactory<UserEntity> by lazy {
         monarchy.createDataSourceFactory { realm ->
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataAPI.kt
index bbeff18c01302a49f67f77748673f56492c69f3e..b283d518458eb674fbe720bebbe57db1ac24f225 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataAPI.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataAPI.kt
@@ -27,11 +27,13 @@ internal interface AccountDataAPI {
      * Set some account_data for the client.
      *
      * @param userId the user id
-     * @param type   the type
+     * @param type the type
      * @param params the put params
      */
     @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/account_data/{type}")
-    suspend fun setAccountData(@Path("userId") userId: String,
-                               @Path("type") type: String,
-                               @Body params: Any)
+    suspend fun setAccountData(
+            @Path("userId") userId: String,
+            @Path("type") type: String,
+            @Body params: Any
+    )
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateUserAccountDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateUserAccountDataTask.kt
index 88db381852ffcf66e09221db6180dbcef964fde2..ff0e960f0fdc4b07958e08b887b70f1c16e3b345 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateUserAccountDataTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateUserAccountDataTask.kt
@@ -35,8 +35,9 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa
         fun getData(): Any
     }
 
-    data class IdentityParams(override val type: String = UserAccountDataTypes.TYPE_IDENTITY_SERVER,
-                              private val identityContent: IdentityServerContent
+    data class IdentityParams(
+            override val type: String = UserAccountDataTypes.TYPE_IDENTITY_SERVER,
+            private val identityContent: IdentityServerContent
     ) : Params {
 
         override fun getData(): Any {
@@ -44,8 +45,9 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa
         }
     }
 
-    data class AcceptedTermsParams(override val type: String = UserAccountDataTypes.TYPE_ACCEPTED_TERMS,
-                                   private val acceptedTermsContent: AcceptedTermsContent
+    data class AcceptedTermsParams(
+            override val type: String = UserAccountDataTypes.TYPE_ACCEPTED_TERMS,
+            private val acceptedTermsContent: AcceptedTermsContent
     ) : Params {
 
         override fun getData(): Any {
@@ -54,8 +56,9 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa
     }
 
     // TODO Use [UserAccountDataDirectMessages] class?
-    data class DirectChatParams(override val type: String = UserAccountDataTypes.TYPE_DIRECT_MESSAGES,
-                                private val directMessages: Map<String, List<String>>
+    data class DirectChatParams(
+            override val type: String = UserAccountDataTypes.TYPE_DIRECT_MESSAGES,
+            private val directMessages: Map<String, List<String>>
     ) : Params {
 
         override fun getData(): Any {
@@ -63,8 +66,9 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa
         }
     }
 
-    data class BreadcrumbsParams(override val type: String = UserAccountDataTypes.TYPE_BREADCRUMBS,
-                                 private val breadcrumbsContent: BreadcrumbsContent
+    data class BreadcrumbsParams(
+            override val type: String = UserAccountDataTypes.TYPE_BREADCRUMBS,
+            private val breadcrumbsContent: BreadcrumbsContent
     ) : Params {
 
         override fun getData(): Any {
@@ -72,24 +76,29 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa
         }
     }
 
-    data class AllowedWidgets(override val type: String = UserAccountDataTypes.TYPE_ALLOWED_WIDGETS,
-                              private val allowedWidgetsContent: AllowedWidgetsContent) : Params {
+    data class AllowedWidgets(
+            override val type: String = UserAccountDataTypes.TYPE_ALLOWED_WIDGETS,
+            private val allowedWidgetsContent: AllowedWidgetsContent
+    ) : Params {
 
         override fun getData(): Any {
             return allowedWidgetsContent
         }
     }
 
-    data class IntegrationProvisioning(override val type: String = UserAccountDataTypes.TYPE_INTEGRATION_PROVISIONING,
-                                       private val integrationProvisioningContent: IntegrationProvisioningContent) : Params {
+    data class IntegrationProvisioning(
+            override val type: String = UserAccountDataTypes.TYPE_INTEGRATION_PROVISIONING,
+            private val integrationProvisioningContent: IntegrationProvisioningContent
+    ) : Params {
 
         override fun getData(): Any {
             return integrationProvisioningContent
         }
     }
 
-    data class AnyParams(override val type: String,
-                         private val any: Any
+    data class AnyParams(
+            override val type: String,
+            private val any: Any
     ) : Params {
         override fun getData(): Any {
             return any
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UserAccountDataDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UserAccountDataDataSource.kt
index 2c3d660333ec9dba8d0ed4bb9726a64580a3ade7..39f155096ac37ea458a6dd8724977ea08906f87d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UserAccountDataDataSource.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UserAccountDataDataSource.kt
@@ -31,9 +31,11 @@ import org.matrix.android.sdk.internal.database.model.UserAccountDataEntityField
 import org.matrix.android.sdk.internal.di.SessionDatabase
 import javax.inject.Inject
 
-internal class UserAccountDataDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
-                                                             private val realmSessionProvider: RealmSessionProvider,
-                                                             private val accountDataMapper: AccountDataMapper) {
+internal class UserAccountDataDataSource @Inject constructor(
+        @SessionDatabase private val monarchy: Monarchy,
+        private val realmSessionProvider: RealmSessionProvider,
+        private val accountDataMapper: AccountDataMapper
+) {
 
     fun getAccountDataEvent(type: String): UserAccountDataEvent? {
         return getAccountDataEvents(setOf(type)).firstOrNull()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt
index 06508def1c4e2787e75874803d70d8da26951e65..51e6812a8bd532377a1f302ae923c5dd0d194625 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt
@@ -41,10 +41,12 @@ internal interface CreateWidgetTask : Task<CreateWidgetTask.Params, String> {
     )
 }
 
-internal class DefaultCreateWidgetTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
-                                                           private val roomAPI: RoomAPI,
-                                                           @UserId private val userId: String,
-                                                           private val globalErrorReceiver: GlobalErrorReceiver) : CreateWidgetTask {
+internal class DefaultCreateWidgetTask @Inject constructor(
+        @SessionDatabase private val monarchy: Monarchy,
+        private val roomAPI: RoomAPI,
+        @UserId private val userId: String,
+        private val globalErrorReceiver: GlobalErrorReceiver
+) : CreateWidgetTask {
 
     override suspend fun execute(params: CreateWidgetTask.Params): String {
         val response = executeRequest(globalErrorReceiver) {
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 1da682791618ff56e64b84ec3aafe41878202306..2665809d9a7eb277a7a04eab00efc4c735c53b23 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
@@ -27,8 +27,10 @@ import timber.log.Timber
 import java.lang.reflect.Type
 import javax.inject.Inject
 
-internal class DefaultWidgetPostAPIMediator @Inject constructor(private val moshi: Moshi,
-                                                                private val widgetPostMessageAPIProvider: WidgetPostMessageAPIProvider) :
+internal class DefaultWidgetPostAPIMediator @Inject constructor(
+        private val moshi: Moshi,
+        private val widgetPostMessageAPIProvider: WidgetPostMessageAPIProvider
+) :
         WidgetPostAPIMediator {
 
     private val jsonAdapter = moshi.adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE)
@@ -95,7 +97,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
     /**
      * Send a boolean response.
      *
-     * @param response  the response
+     * @param response the response
      * @param eventData the modular data
      */
     override fun sendBoolResponse(response: Boolean, eventData: JsonDict) {
@@ -106,7 +108,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
     /**
      * Send an integer response.
      *
-     * @param response  the response
+     * @param response the response
      * @param eventData the modular data
      */
     override fun sendIntegerResponse(response: Int, eventData: JsonDict) {
@@ -116,7 +118,9 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
     /**
      * Send an object response.
      *
-     * @param response  the response
+     * @param T the Json type
+     * @param type the type
+     * @param response the response
      * @param eventData the modular data
      */
     override fun <T> sendObjectResponse(type: Type, response: T?, eventData: JsonDict) {
@@ -145,7 +149,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
     /**
      * Send an error.
      *
-     * @param message   the error message
+     * @param message the error message
      * @param eventData the modular data
      */
     override fun sendError(message: String, eventData: JsonDict) {
@@ -162,7 +166,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
     /**
      * Send the response to the javascript.
      *
-     * @param jsString  the response data
+     * @param jsString the response data
      * @param eventData the modular data
      */
     private fun sendResponse(jsString: String, eventData: JsonDict) = uiHandler.post {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetService.kt
index 53a435d2172c127b22120322974c4b55d66f0fce..7b2edf2dbf3f22b189a5018e07ee1015c36a377d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetService.kt
@@ -26,9 +26,11 @@ import org.matrix.android.sdk.api.session.widgets.model.Widget
 import javax.inject.Inject
 import javax.inject.Provider
 
-internal class DefaultWidgetService @Inject constructor(private val widgetManager: WidgetManager,
-                                                        private val widgetURLFormatter: WidgetURLFormatter,
-                                                        private val widgetPostAPIMediator: Provider<WidgetPostAPIMediator>) :
+internal class DefaultWidgetService @Inject constructor(
+        private val widgetManager: WidgetManager,
+        private val widgetURLFormatter: WidgetURLFormatter,
+        private val widgetPostAPIMediator: Provider<WidgetPostAPIMediator>
+) :
         WidgetService {
 
     override fun getWidgetURLFormatter(): WidgetURLFormatter {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetURLFormatter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetURLFormatter.kt
index 5879b6244676e362829089ec47318a636969ee00..019edf21b663cc4bfcea4d57f933511eb9421b92 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetURLFormatter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetURLFormatter.kt
@@ -30,9 +30,10 @@ import org.matrix.android.sdk.internal.session.widgets.token.GetScalarTokenTask
 import javax.inject.Inject
 
 @SessionScope
-internal class DefaultWidgetURLFormatter @Inject constructor(private val integrationManager: IntegrationManager,
-                                                             private val getScalarTokenTask: GetScalarTokenTask,
-                                                             private val matrixConfiguration: MatrixConfiguration
+internal class DefaultWidgetURLFormatter @Inject constructor(
+        private val integrationManager: IntegrationManager,
+        private val getScalarTokenTask: GetScalarTokenTask,
+        private val matrixConfiguration: MatrixConfiguration
 ) : IntegrationManagerService.Listener, WidgetURLFormatter, SessionLifecycleObserver {
 
     private lateinit var currentConfig: IntegrationManagerConfig
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt
index 07ed91c1790ff82ac64864a968794ff3981f498f..3f7db93b97d23efe45721238f63c3b03c641a8d7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt
@@ -45,12 +45,14 @@ import org.matrix.android.sdk.internal.session.widgets.helper.extractWidgetSeque
 import javax.inject.Inject
 
 @SessionScope
-internal class WidgetManager @Inject constructor(private val integrationManager: IntegrationManager,
-                                                 private val userAccountDataDataSource: UserAccountDataDataSource,
-                                                 private val stateEventDataSource: StateEventDataSource,
-                                                 private val createWidgetTask: CreateWidgetTask,
-                                                 private val widgetFactory: WidgetFactory,
-                                                 @UserId private val userId: String) :
+internal class WidgetManager @Inject constructor(
+        private val integrationManager: IntegrationManager,
+        private val userAccountDataDataSource: UserAccountDataDataSource,
+        private val stateEventDataSource: StateEventDataSource,
+        private val createWidgetTask: CreateWidgetTask,
+        private val widgetFactory: WidgetFactory,
+        @UserId private val userId: String
+) :
 
         IntegrationManagerService.Listener, SessionLifecycleObserver {
 
@@ -103,8 +105,10 @@ internal class WidgetManager @Inject constructor(private val integrationManager:
         return widgetFactory.computeURL(widget, isLightTheme)
     }
 
-    private fun List<Event>.mapEventsToWidgets(widgetTypes: Set<String>? = null,
-                                               excludedTypes: Set<String>? = null): List<Widget> {
+    private fun List<Event>.mapEventsToWidgets(
+            widgetTypes: Set<String>? = null,
+            excludedTypes: Set<String>? = null
+    ): List<Widget> {
         val widgetEvents = this
         // Widget id -> widget
         val widgets: MutableMap<String, Widget> = HashMap()
@@ -149,8 +153,10 @@ internal class WidgetManager @Inject constructor(private val integrationManager:
         return widgetsAccountData.mapToWidgets(widgetTypes, excludedTypes)
     }
 
-    private fun UserAccountDataEvent.mapToWidgets(widgetTypes: Set<String>? = null,
-                                                  excludedTypes: Set<String>? = null): List<Widget> {
+    private fun UserAccountDataEvent.mapToWidgets(
+            widgetTypes: Set<String>? = null,
+            excludedTypes: Set<String>? = null
+    ): List<Widget> {
         return extractWidgetSequence(widgetFactory)
                 .filter {
                     val widgetType = it.widgetContent.type ?: return@filter false
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 b871a317c88c5217afda2c97f385e2918b943d15..2a4af9ffaaccef88372a5c76ecd20edd269d001d 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
@@ -27,12 +27,17 @@ internal interface WidgetsAPI {
      * Register to the server.
      *
      * @param body the body content (Ref: https://github.com/matrix-org/matrix-doc/pull/1961)
+     * @param version the widget API version
      */
     @POST("register")
-    suspend fun register(@Body body: OpenIdToken,
-                         @Query("v") version: String?): RegisterWidgetResponse
+    suspend fun register(
+            @Body body: OpenIdToken,
+            @Query("v") version: String?
+    ): RegisterWidgetResponse
 
     @GET("account")
-    suspend fun validateToken(@Query("scalar_token") scalarToken: String?,
-                              @Query("v") version: String?)
+    suspend fun validateToken(
+            @Query("scalar_token") scalarToken: String?,
+            @Query("v") version: String?
+    )
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPIProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPIProvider.kt
index 48c8fcdb03340d49e2508b874be8fdfcc864d891..25caadbade9d96dfd870ba600fbac9bf0485e409 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPIProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPIProvider.kt
@@ -24,8 +24,10 @@ import org.matrix.android.sdk.internal.session.SessionScope
 import javax.inject.Inject
 
 @SessionScope
-internal class WidgetsAPIProvider @Inject constructor(@Unauthenticated private val okHttpClient: Lazy<OkHttpClient>,
-                                                      private val retrofitFactory: RetrofitFactory) {
+internal class WidgetsAPIProvider @Inject constructor(
+        @Unauthenticated private val okHttpClient: Lazy<OkHttpClient>,
+        private val retrofitFactory: RetrofitFactory
+) {
 
     // Map to keep one WidgetAPI instance by serverUrl
     private val widgetsAPIs = mutableMapOf<String, WidgetsAPI>()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt
index a5e74a8af0fe400fdd25a96ec14394ca616b2ff6..8bd61a7bdf5ffdb962bd7acb56e353e6861ef4e3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt
@@ -33,11 +33,13 @@ import org.matrix.android.sdk.internal.session.user.UserDataSource
 import java.net.URLEncoder
 import javax.inject.Inject
 
-internal class WidgetFactory @Inject constructor(private val userDataSource: UserDataSource,
-                                                 private val realmSessionProvider: RealmSessionProvider,
-                                                 private val displayNameResolver: DisplayNameResolver,
-                                                 private val urlResolver: ContentUrlResolver,
-                                                 @UserId private val userId: String) {
+internal class WidgetFactory @Inject constructor(
+        private val userDataSource: UserDataSource,
+        private val realmSessionProvider: RealmSessionProvider,
+        private val displayNameResolver: DisplayNameResolver,
+        private val urlResolver: ContentUrlResolver,
+        @UserId private val userId: String
+) {
 
     fun create(widgetEvent: Event): Widget? {
         val widgetContent = widgetEvent.content.toModel<WidgetContent>()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/token/GetScalarTokenTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/token/GetScalarTokenTask.kt
index 17797cad52d4c29213b0e6c7adc8c87429f7af49..49ae52afaaed17155ac8c1bcfe3efcd2fab657fe 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/token/GetScalarTokenTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/token/GetScalarTokenTask.kt
@@ -37,9 +37,11 @@ internal interface GetScalarTokenTask : Task<GetScalarTokenTask.Params, String>
 
 private const val WIDGET_API_VERSION = "1.1"
 
-internal class DefaultGetScalarTokenTask @Inject constructor(private val widgetsAPIProvider: WidgetsAPIProvider,
-                                                             private val scalarTokenStore: ScalarTokenStore,
-                                                             private val getOpenIdTokenTask: GetOpenIdTokenTask) : GetScalarTokenTask {
+internal class DefaultGetScalarTokenTask @Inject constructor(
+        private val widgetsAPIProvider: WidgetsAPIProvider,
+        private val scalarTokenStore: ScalarTokenStore,
+        private val getOpenIdTokenTask: GetOpenIdTokenTask
+) : GetScalarTokenTask {
 
     override suspend fun execute(params: GetScalarTokenTask.Params): String {
         val widgetsAPI = widgetsAPIProvider.get(params.serverUrl)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/ConfigurableTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/ConfigurableTask.kt
index bc80cf7ee8bd3fd7af38f5f6d07b16a098f264ef..eead25b57c008eb3d953e3e019886c1bf526e931 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/ConfigurableTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/ConfigurableTask.kt
@@ -21,8 +21,9 @@ import org.matrix.android.sdk.api.NoOpMatrixCallback
 import org.matrix.android.sdk.api.util.Cancelable
 import java.util.UUID
 
-internal fun <PARAMS, RESULT> Task<PARAMS, RESULT>.configureWith(params: PARAMS,
-                                                                 init: (ConfigurableTask.Builder<PARAMS, RESULT>.() -> Unit) = {}
+internal fun <PARAMS, RESULT> Task<PARAMS, RESULT>.configureWith(
+        params: PARAMS,
+        init: (ConfigurableTask.Builder<PARAMS, RESULT>.() -> Unit) = {}
 ): ConfigurableTask<PARAMS, RESULT> {
     return ConfigurableTask.Builder(this, params).apply(init).build()
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/CoroutineSequencer.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/CoroutineSequencer.kt
index 80081e318618d790d1687515973cd3f5b6d8030d..dd4c5e762343ddda325a701078b1cf1caaea0c97 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/CoroutineSequencer.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/CoroutineSequencer.kt
@@ -24,6 +24,7 @@ import kotlinx.coroutines.sync.withPermit
  */
 internal interface CoroutineSequencer {
     /**
+     * @param T generic type
      * @param block the suspendable block to execute
      * @return the result of the block
      */
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/TaskExecutor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/TaskExecutor.kt
index 57574a96fa9f120d705b421c6176d5a50c8cf343..5e685bd546d826caccf7650f5335d8c8e7f2ef53 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/TaskExecutor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/TaskExecutor.kt
@@ -57,11 +57,11 @@ internal class TaskExecutor @Inject constructor(private val coroutineDispatchers
     fun cancelAll() = executorScope.coroutineContext.cancelChildren()
 
     private fun TaskThread.toDispatcher() = when (this) {
-        TaskThread.MAIN        -> coroutineDispatchers.main
+        TaskThread.MAIN -> coroutineDispatchers.main
         TaskThread.COMPUTATION -> coroutineDispatchers.computation
-        TaskThread.IO          -> coroutineDispatchers.io
-        TaskThread.CALLER      -> EmptyCoroutineContext
-        TaskThread.CRYPTO      -> coroutineDispatchers.crypto
-        TaskThread.DM_VERIF    -> coroutineDispatchers.dmVerif
+        TaskThread.IO -> coroutineDispatchers.io
+        TaskThread.CALLER -> EmptyCoroutineContext
+        TaskThread.CRYPTO -> coroutineDispatchers.crypto
+        TaskThread.DM_VERIF -> coroutineDispatchers.dmVerif
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CancelableWork.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CancelableWork.kt
index 6b04cea936a8b96450c900eea370fde3580565fd..2240a408efc87a90d76878df08b07f3daa9cbcd2 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CancelableWork.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CancelableWork.kt
@@ -20,8 +20,10 @@ import androidx.work.WorkManager
 import org.matrix.android.sdk.api.util.Cancelable
 import java.util.UUID
 
-internal class CancelableWork(private val workManager: WorkManager,
-                              private val workId: UUID) : Cancelable {
+internal class CancelableWork(
+        private val workManager: WorkManager,
+        private val workId: UUID
+) : Cancelable {
 
     override fun cancel() {
         workManager.cancelWorkById(workId)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Glob.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Glob.kt
index 60f9609586858e061bcddc847ad04dae3477e49e..a4aae803480cf546a41c0e4320d7613372bb9861 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Glob.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Glob.kt
@@ -27,9 +27,9 @@ internal fun String.simpleGlobToRegExp(): String {
         // append("^")
         string.forEach { char ->
             when (char) {
-                '*'  -> append(".*")
-                '?'  -> append(".")
-                '.'  -> append("\\.")
+                '*' -> append(".*")
+                '?' -> append(".")
+                '.' -> append("\\.")
                 '\\' -> append("\\\\")
                 else -> append(char)
             }
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 94aa238789fd9dbc8e28bb598a66e2fa744ab3c0..6e6007f491a8e089260f701d8cface64f62236c7 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
@@ -53,12 +53,12 @@ internal object JsonCanonicalizer {
     /**
      * Canonicalize a JSON element.
      *
-     * @param src the src
+     * @param any the src
      * @return the canonicalize element
      */
     private fun canonicalizeRecursive(any: Any): String {
         when (any) {
-            is JSONArray  -> {
+            is JSONArray -> {
                 // Canonicalize each element of the array
                 return (0 until any.length()).joinToString(separator = ",", prefix = "[", postfix = "]") {
                     canonicalizeRecursive(any.get(it))
@@ -88,8 +88,8 @@ internal object JsonCanonicalizer {
                     append("}")
                 }
             }
-            is String     -> return JSONObject.quote(any)
-            else          -> return any.toString()
+            is String -> return JSONObject.quote(any)
+            else -> return any.toString()
         }
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/LogUtil.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/LogUtil.kt
index ffad0b856c368d750256bfb254ae2643fa977e9f..2306ddf850b633c3895d5769237af3ae90e4d10a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/LogUtil.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/LogUtil.kt
@@ -33,10 +33,12 @@ internal fun <T> Collection<T>.logLimit(maxQuantity: Int = 5): String {
     }
 }
 
-internal suspend fun <T> logDuration(message: String,
-                                     loggerTag: LoggerTag,
-                                     clock: Clock,
-                                     block: suspend () -> T): T {
+internal suspend fun <T> logDuration(
+        message: String,
+        loggerTag: LoggerTag,
+        clock: Clock,
+        block: suspend () -> T
+): T {
     Timber.tag(loggerTag.value).d("$message -- BEGIN")
     val start = clock.epochMillis()
     val result = logRamUsage(message) {
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 d9fd312a6fc1d4a9d2635eff929a219cd88c6a75..c6a417f6eb6ee564ab396ccf308504df02f061f9 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
@@ -54,7 +54,7 @@ internal fun convertFromUTF8(s: String): String {
 /**
  * Returns whether a string contains an occurrence of another, as a standalone word, regardless of case.
  *
- * @param subString  the string to search for
+ * @param subString the string to search for
  * @return whether a match was found
  */
 internal fun String.caseInsensitiveFind(subString: String): Boolean {
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 fbbec1a100985df2227a000d373104c27bae3f35..cbaec586d0542a31c2436397c5650f655b944377 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
@@ -32,9 +32,9 @@ internal fun String.isValidUrl(): Boolean {
  */
 internal fun String.ensureProtocol(): String {
     return when {
-        isEmpty()           -> this
+        isEmpty() -> this
         !startsWith("http") -> "https://$this"
-        else                -> this
+        else -> this
     }
 }
 
@@ -43,8 +43,8 @@ internal fun String.ensureProtocol(): String {
  */
 internal fun String.ensureTrailingSlash(): String {
     return when {
-        isEmpty()      -> this
+        isEmpty() -> this
         !endsWith("/") -> "$this/"
-        else           -> this
+        else -> this
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/database/RealmMigrator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/database/RealmMigrator.kt
index 8f3c89f2d4282f9c058c9ab7654e5ccd1e8f429a..8da1bed97e0c5385e9aae4133fb278c16b078816 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/database/RealmMigrator.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/database/RealmMigrator.kt
@@ -20,8 +20,10 @@ import io.realm.DynamicRealm
 import io.realm.RealmObjectSchema
 import timber.log.Timber
 
-internal abstract class RealmMigrator(private val realm: DynamicRealm,
-                                      private val targetSchemaVersion: Int) {
+internal abstract class RealmMigrator(
+        private val realm: DynamicRealm,
+        private val targetSchemaVersion: Int
+) {
     fun perform() {
         Timber.d("Migrate ${realm.configuration.realmFileName} to $targetSchemaVersion")
         doMigrate(realm)
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 0d4a5ac28f25400a56b3c1a39ef498cca8cb6c98..003bdab9cbd793f11d105266bf0550a187ce3bb4 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
@@ -75,7 +75,8 @@ internal class DefaultGetWellknownTask @Inject constructor(
      * - validate homeserver url and identity server url if provide in .well-known result
      * - return action and .well-known data
      *
-     * @param domain: homeserver domain, deduced from mx userId (ex: "matrix.org" from userId "@user:matrix.org")
+     * @param domain homeserver domain, deduced from mx userId (ex: "matrix.org" from userId "@user:matrix.org")
+     * @param client Http client to perform the request
      */
     private suspend fun findClientConfig(domain: String, client: OkHttpClient): WellknownResult {
         val wellKnownAPI = retrofitFactory.create(client, "https://dummy.org")
@@ -100,25 +101,25 @@ internal class DefaultGetWellknownTask @Inject constructor(
             }
         } catch (throwable: Throwable) {
             when (throwable) {
-                is UnrecognizedCertificateException        -> {
+                is UnrecognizedCertificateException -> {
                     throw Failure.UnrecognizedCertificateFailure(
                             "https://$domain",
                             throwable.fingerprint
                     )
                 }
-                is Failure.NetworkConnection               -> {
+                is Failure.NetworkConnection -> {
                     WellknownResult.Ignore
                 }
-                is Failure.OtherServerError                -> {
+                is Failure.OtherServerError -> {
                     when (throwable.httpCode) {
                         HttpsURLConnection.HTTP_NOT_FOUND -> WellknownResult.Ignore
-                        else                              -> WellknownResult.FailPrompt(null, null)
+                        else -> WellknownResult.FailPrompt(null, null)
                     }
                 }
                 is MalformedJsonException, is EOFException -> {
                     WellknownResult.FailPrompt(null, null)
                 }
-                else                                       -> {
+                else -> {
                     throw throwable
                 }
             }
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 95b3662c670c6973e2132ba1cc50f378c196a449..52146ef484b81746b89c66be779d260bbd1e1ef7 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
@@ -27,6 +27,7 @@ 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
 import org.matrix.android.sdk.internal.session.pushers.AddPusherWorker
+import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.DeactivateLiveLocationShareWorker
 import org.matrix.android.sdk.internal.session.room.send.MultipleEventSendingDispatcherWorker
 import org.matrix.android.sdk.internal.session.room.send.RedactEventWorker
 import org.matrix.android.sdk.internal.session.room.send.SendEventWorker
@@ -48,25 +49,27 @@ internal class MatrixWorkerFactory @Inject constructor(private val sessionManage
     ): ListenableWorker? {
         Timber.d("MatrixWorkerFactory.createWorker for $workerClassName")
         return when (workerClassName) {
-            CheckFactoryWorker::class.java.name                   ->
+            CheckFactoryWorker::class.java.name ->
                 CheckFactoryWorker(appContext, workerParameters, true)
-            AddPusherWorker::class.java.name                      ->
+            AddPusherWorker::class.java.name ->
                 AddPusherWorker(appContext, workerParameters, sessionManager)
-            GetGroupDataWorker::class.java.name                   ->
+            GetGroupDataWorker::class.java.name ->
                 GetGroupDataWorker(appContext, workerParameters, sessionManager)
             MultipleEventSendingDispatcherWorker::class.java.name ->
                 MultipleEventSendingDispatcherWorker(appContext, workerParameters, sessionManager)
-            RedactEventWorker::class.java.name                    ->
+            RedactEventWorker::class.java.name ->
                 RedactEventWorker(appContext, workerParameters, sessionManager)
-            SendEventWorker::class.java.name                      ->
+            SendEventWorker::class.java.name ->
                 SendEventWorker(appContext, workerParameters, sessionManager)
-            SyncWorker::class.java.name                           ->
+            SyncWorker::class.java.name ->
                 SyncWorker(appContext, workerParameters, sessionManager)
-            UpdateTrustWorker::class.java.name                    ->
+            UpdateTrustWorker::class.java.name ->
                 UpdateTrustWorker(appContext, workerParameters, sessionManager)
-            UploadContentWorker::class.java.name                  ->
+            UploadContentWorker::class.java.name ->
                 UploadContentWorker(appContext, workerParameters, sessionManager)
-            else                                                  -> {
+            DeactivateLiveLocationShareWorker::class.java.name ->
+                DeactivateLiveLocationShareWorker(appContext, workerParameters, sessionManager)
+            else -> {
                 Timber.w("No worker defined on MatrixWorkerFactory for $workerClassName will delegate to default.")
                 // Return null to delegate to the default WorkerFactory.
                 null
@@ -78,9 +81,11 @@ internal class MatrixWorkerFactory @Inject constructor(private val sessionManage
      * This worker is launched by the factory with the isCreatedByMatrixWorkerFactory flag to true.
      * If the MatrixWorkerFactory is not set up, it will default to the other constructor and it will throw
      */
-    class CheckFactoryWorker(context: Context,
-                             workerParameters: WorkerParameters,
-                             private val isCreatedByMatrixWorkerFactory: Boolean) :
+    class CheckFactoryWorker(
+            context: Context,
+            workerParameters: WorkerParameters,
+            private val isCreatedByMatrixWorkerFactory: Boolean
+    ) :
             CoroutineWorker(context, workerParameters) {
 
         // Called by WorkManager if there is no MatrixWorkerFactory
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us000InitMatrix.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us000InitMatrix.kt
new file mode 100644
index 0000000000000000000000000000000000000000..06c6cc9ef9d9eb073aaee0140ae6d7a92f781cff
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us000InitMatrix.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("unused")
+
+package org.matrix.android.sdk.userstories
+
+/**
+ * ### Title
+ * Init a Matrix object.
+ *
+ * ### Required APIs:
+ * - [org.matrix.android.sdk.api.Matrix] constructor
+ */
+class Us000InitMatrix private constructor()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us100SignIn.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us100SignIn.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f508a75db7476f630eefd6dc88393b87816de6aa
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us100SignIn.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("unused")
+
+package org.matrix.android.sdk.userstories
+
+/**
+ * ### Title
+ * Sign in to an existing account.
+ *
+ * #### Required APIs:
+ * - [org.matrix.android.sdk.api.Matrix.authenticationService]
+ * - [org.matrix.android.sdk.api.auth.AuthenticationService.getLoginFlow]
+ * - [org.matrix.android.sdk.api.auth.AuthenticationService.getLoginWizard]
+ * - [org.matrix.android.sdk.api.auth.login.LoginWizard.login]
+ */
+class Us100SignIn private constructor()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us150VerifySession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us150VerifySession.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ac56cc35dd9afa57f7c1274f6385efcb11a24bb1
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us150VerifySession.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("unused")
+
+package org.matrix.android.sdk.userstories
+
+/**
+ * ### Title
+ * Verify a Session after a Sign in.
+ *
+ * #### Required APIs:
+ * - TODO
+ */
+class Us150VerifySession private constructor()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us190SignOut.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us190SignOut.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0c74c0dfef0e2b60703417dc6b21a0cf784489ee
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us190SignOut.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("unused")
+
+package org.matrix.android.sdk.userstories
+
+/**
+ * ### Title
+ * Sign out.
+ *
+ * #### Required APIs:
+ * - TODO
+ */
+class Us190SignOut private constructor()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us200RoomList.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us200RoomList.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1f0b2e41038d6858196866fdb9c5976a1dd17f3f
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us200RoomList.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("unused")
+
+package org.matrix.android.sdk.userstories
+
+/**
+ * ### Title
+ * Get the Room list.
+ *
+ * #### Required APIs:
+ * - TODO
+ */
+class Us200RoomList private constructor()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us300RoomTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us300RoomTimeline.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5db06f95f6a74fd3410f3ca5feb4043440cb82b6
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us300RoomTimeline.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("unused")
+
+package org.matrix.android.sdk.userstories
+
+/**
+ * ### Title
+ * Display a Room timeline, and navigate backward and forward.
+ *
+ * #### Required APIs:
+ * - TODO
+ */
+class Us300RoomTimeline private constructor()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us350RoomTimelineFromPermalink.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us350RoomTimelineFromPermalink.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5e0f6d3b3d9c4fcd0d37b6b51e6fd39132e4ee19
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us350RoomTimelineFromPermalink.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("unused")
+
+package org.matrix.android.sdk.userstories
+
+/**
+ * ### Title
+ * Display a Room timeline at a specific point.
+ *
+ * #### Required APIs:
+ * - TODO
+ */
+class Us350RoomTimelineFromPermalink private constructor()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us400RoomSendContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us400RoomSendContent.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3f72cd0b9e9f89d270cffd8a5d655e41aab286c1
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us400RoomSendContent.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("unused")
+
+package org.matrix.android.sdk.userstories
+
+/**
+ * ### Title
+ * Send content to a room, including monitoring the sending state.
+ *
+ * #### Required APIs:
+ * - TODO
+ */
+class Us400RoomSendContent private constructor()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us500Notification.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us500Notification.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c5c2107fa620319bf18980074b05da843138dfa8
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us500Notification.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("unused")
+
+package org.matrix.android.sdk.userstories
+
+/**
+ * ### Title
+ * Get notified when new Events are received.
+ *
+ * #### Required APIs:
+ * - TODO
+ */
+class Us500Notification private constructor()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us600SyncWithTheServer.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us600SyncWithTheServer.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6b8fb87df7320767e5fdf14521fca4586f2dbf16
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us600SyncWithTheServer.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("unused")
+
+package org.matrix.android.sdk.userstories
+
+/**
+ * ### Title
+ * Manage the sync with the server.
+ *
+ * #### Required APIs:
+ * - TODO
+ */
+class Us600SyncWithTheServer private constructor()
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersionTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersionTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..413af9c434f7bbd6c5baf9a72dd053d66f29ef9f
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersionTest.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.auth.version
+
+import org.amshove.kluent.internal.assertEquals
+import org.junit.Test
+
+class HomeServerVersionTest {
+
+    @Test
+    fun `given a semantic version, when parsing, then converts to home server version`() {
+        val supportedVersions = listOf(
+                case("1.5", expected = aVersion(1, 5, 0)),
+                case("0.5.1", expected = aVersion(0, 5, 1)),
+                case("1.0.0", expected = aVersion(1, 0, 0)),
+                case("1.10.3", expected = aVersion(1, 10, 3)),
+        ).withPrefixes("v", "r")
+
+        val unsupportedVersions = listOf(
+                case("v-1.5.1", expected = null),
+                case("1.4.", expected = null),
+                case("1.5.1.", expected = null),
+                case("r1", expected = null),
+                case("a", expected = null),
+                case("1a.2b.3c", expected = null),
+                case("r", expected = null),
+        )
+
+        (supportedVersions + unsupportedVersions).forEach { (input, expected) ->
+            val result = HomeServerVersion.parse(input)
+
+            assertEquals(expected, result, "Expected $input to be $expected but got $result")
+        }
+    }
+}
+
+private fun aVersion(major: Int, minor: Int, patch: Int) = HomeServerVersion(major, minor, patch)
+private fun case(input: String, expected: HomeServerVersion?) = Case(input, expected)
+
+private fun List<Case>.withPrefixes(vararg prefixes: String) = map { case ->
+    prefixes.map { prefix -> case.copy(input = "$prefix${case.input}") }
+}.flatten()
+
+private data class Case(val input: String, val expected: HomeServerVersion?)
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapperTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapperTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..47d5f465256be23cbc4edc5ff07be4743423ea75
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapperTest.kt
@@ -0,0 +1,56 @@
+/*
+ * 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.database.mapper
+
+import com.squareup.moshi.Moshi
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.Test
+import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
+import org.matrix.android.sdk.api.session.room.model.message.LocationInfo
+import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
+import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
+
+private const val ANY_USER_ID = "a-user-id"
+private const val ANY_ACTIVE_STATE = true
+private const val ANY_TIMEOUT = 123L
+private val A_LOCATION_INFO = LocationInfo("a-geo-uri")
+
+class LiveLocationShareAggregatedSummaryMapperTest {
+
+    private val mapper = LiveLocationShareAggregatedSummaryMapper()
+
+    @Test
+    fun `given an entity then result should be mapped correctly`() {
+        val entity = anEntity(content = MessageBeaconLocationDataContent(locationInfo = A_LOCATION_INFO))
+
+        val summary = mapper.map(entity)
+
+        summary shouldBeEqualTo LiveLocationShareAggregatedSummary(
+                userId = ANY_USER_ID,
+                isActive = ANY_ACTIVE_STATE,
+                endOfLiveTimestampMillis = ANY_TIMEOUT,
+                lastLocationDataContent = MessageBeaconLocationDataContent(locationInfo = A_LOCATION_INFO)
+        )
+    }
+
+    private fun anEntity(content: MessageBeaconLocationDataContent) = LiveLocationShareAggregatedSummaryEntity(
+            userId = ANY_USER_ID,
+            isActive = ANY_ACTIVE_STATE,
+            endOfLiveTimestampMillis = ANY_TIMEOUT,
+            lastLocationContent = Moshi.Builder().build().adapter(MessageBeaconLocationDataContent::class.java).toJson(content)
+    )
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollAggregationProcessorTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollAggregationProcessorTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..837bbeea268b60defcf9da04a6437c3b501db454
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollAggregationProcessorTest.kt
@@ -0,0 +1,162 @@
+/*
+ * 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.session.room.aggregation.poll
+
+import io.mockk.every
+import io.mockk.mockk
+import io.realm.RealmList
+import io.realm.RealmModel
+import io.realm.RealmQuery
+import org.amshove.kluent.shouldBeFalse
+import org.amshove.kluent.shouldBeTrue
+import org.junit.Before
+import org.junit.Test
+import org.matrix.android.sdk.api.session.Session
+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.getTimelineEvent
+import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
+import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity
+import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntityFields
+import org.matrix.android.sdk.internal.database.model.PollResponseAggregatedSummaryEntity
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.AN_EVENT_ID
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.AN_INVALID_POLL_RESPONSE_EVENT
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_BROKEN_POLL_REPLACE_EVENT
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_POLL_END_EVENT
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_POLL_REFERENCE_EVENT
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_POLL_REPLACE_EVENT
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_POLL_RESPONSE_EVENT
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_POLL_RESPONSE_EVENT_WITH_A_WRONG_REFERENCE
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_POLL_START_EVENT
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_ROOM_ID
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_TIMELINE_EVENT
+import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_USER_ID_1
+import org.matrix.android.sdk.test.fakes.FakeRealm
+
+class PollAggregationProcessorTest {
+
+    private val pollAggregationProcessor: PollAggregationProcessor = DefaultPollAggregationProcessor()
+    private val realm = FakeRealm()
+    private val session = mockk<Session>()
+
+    @Before
+    fun setup() {
+        mockEventAnnotationsSummaryEntity()
+        mockRoom(A_ROOM_ID, AN_EVENT_ID)
+        every { session.myUserId } returns A_USER_ID_1
+    }
+
+    @Test
+    fun `given a poll start event, when processing, then is ignored and returns false`() {
+        pollAggregationProcessor.handlePollStartEvent(realm.instance, A_POLL_START_EVENT).shouldBeFalse()
+    }
+
+    @Test
+    fun `given a poll start event with a reference, when processing, then is ignored and returns false`() {
+        pollAggregationProcessor.handlePollStartEvent(realm.instance, A_POLL_REFERENCE_EVENT).shouldBeFalse()
+    }
+
+    @Test
+    fun `given a poll start event with a replace relation but without a target event id, when processing, then is ignored and returns false`() {
+        pollAggregationProcessor.handlePollStartEvent(realm.instance, A_BROKEN_POLL_REPLACE_EVENT).shouldBeFalse()
+    }
+
+    @Test
+    fun `given a poll start event with a replace, when processing, then is processed and returns true`() {
+        pollAggregationProcessor.handlePollStartEvent(realm.instance, A_POLL_REPLACE_EVENT).shouldBeTrue()
+    }
+
+    @Test
+    fun `given a poll response event with a broken reference, when processing, then is ignored and returns false`() {
+        pollAggregationProcessor.handlePollResponseEvent(session, realm.instance, A_POLL_RESPONSE_EVENT_WITH_A_WRONG_REFERENCE).shouldBeFalse()
+    }
+
+    @Test
+    fun `given a poll response event with a reference, when processing, then is processed and returns true`() {
+        every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity()
+        pollAggregationProcessor.handlePollResponseEvent(session, realm.instance, A_POLL_RESPONSE_EVENT).shouldBeTrue()
+    }
+
+    @Test
+    fun `given a poll response event after poll is closed, when processing, then is ignored and returns false`() {
+        every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity().apply {
+            closedTime = (A_POLL_RESPONSE_EVENT.originServerTs ?: 0) - 1
+        }
+        pollAggregationProcessor.handlePollResponseEvent(session, realm.instance, A_POLL_RESPONSE_EVENT).shouldBeFalse()
+    }
+
+    @Test
+    fun `given a poll response event which is already processed, when processing, then is ignored and returns false`() {
+        every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity().apply {
+            sourceEvents = RealmList(A_POLL_RESPONSE_EVENT.eventId)
+        }
+        pollAggregationProcessor.handlePollResponseEvent(session, realm.instance, A_POLL_RESPONSE_EVENT).shouldBeFalse()
+    }
+
+    @Test
+    fun `given a poll response event which is not one of the options, when processing, then is ignored and returns false`() {
+        every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity()
+        pollAggregationProcessor.handlePollResponseEvent(session, realm.instance, AN_INVALID_POLL_RESPONSE_EVENT).shouldBeFalse()
+    }
+
+    @Test
+    fun `given a poll end event, when processing, then is processed and return true`() {
+        every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity()
+        val powerLevelsHelper = mockRedactionPowerLevels(A_USER_ID_1, true)
+        pollAggregationProcessor.handlePollEndEvent(session, powerLevelsHelper, realm.instance, A_POLL_END_EVENT).shouldBeTrue()
+    }
+
+    @Test
+    fun `given a poll end event for my own poll without enough redaction power level, when processing, then is processed and returns true`() {
+        every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity()
+        val powerLevelsHelper = mockRedactionPowerLevels(A_USER_ID_1, false)
+        pollAggregationProcessor.handlePollEndEvent(session, powerLevelsHelper, realm.instance, A_POLL_END_EVENT).shouldBeTrue()
+    }
+
+    @Test
+    fun `given a poll end event without enough redaction power level, when is processed, then is ignored and return false`() {
+        every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity()
+        val powerLevelsHelper = mockRedactionPowerLevels("another-sender-id", false)
+        val event = A_POLL_END_EVENT.copy(senderId = "another-sender-id")
+        pollAggregationProcessor.handlePollEndEvent(session, powerLevelsHelper, realm.instance, event).shouldBeFalse()
+    }
+
+    private inline fun <reified T : RealmModel> RealmQuery<T>.givenEqualTo(fieldName: String, value: String, result: RealmQuery<T>) {
+        every { equalTo(fieldName, value) } returns result
+    }
+
+    private fun mockEventAnnotationsSummaryEntity() {
+        val queryResult = realm.givenWhereReturns(result = EventAnnotationsSummaryEntity())
+        queryResult.givenEqualTo(EventAnnotationsSummaryEntityFields.ROOM_ID, A_POLL_REPLACE_EVENT.roomId!!, queryResult)
+        queryResult.givenEqualTo(EventAnnotationsSummaryEntityFields.EVENT_ID, A_POLL_REPLACE_EVENT.eventId!!, queryResult)
+    }
+
+    private fun mockRoom(
+            roomId: String,
+            eventId: String
+    ) {
+        val room = mockk<Room>()
+        every { session.getRoom(roomId) } returns room
+        every { room.getTimelineEvent(eventId) } returns A_TIMELINE_EVENT
+    }
+
+    private fun mockRedactionPowerLevels(userId: String, isAbleToRedact: Boolean): PowerLevelsHelper {
+        val powerLevelsHelper = mockk<PowerLevelsHelper>()
+        every { powerLevelsHelper.isUserAbleToRedact(userId) } returns isAbleToRedact
+        return powerLevelsHelper
+    }
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollEventsTestData.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollEventsTestData.kt
new file mode 100644
index 0000000000000000000000000000000000000000..129d49633e2f9135500052efdba4093e0394236f
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollEventsTestData.kt
@@ -0,0 +1,171 @@
+/*
+ * 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.session.room.aggregation.poll
+
+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.RelationType
+import org.matrix.android.sdk.api.session.events.model.toContent
+import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent
+import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
+import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent
+import org.matrix.android.sdk.api.session.room.model.message.PollAnswer
+import org.matrix.android.sdk.api.session.room.model.message.PollCreationInfo
+import org.matrix.android.sdk.api.session.room.model.message.PollQuestion
+import org.matrix.android.sdk.api.session.room.model.message.PollResponse
+import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
+import org.matrix.android.sdk.api.session.room.sender.SenderInfo
+import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
+
+object PollEventsTestData {
+    internal const val A_USER_ID_1 = "@user_1:matrix.org"
+    internal const val A_ROOM_ID = "!sUeOGZKsBValPTUMax:matrix.org"
+    internal const val AN_EVENT_ID = "\$vApgexcL8Vfh-WxYKsFKCDooo67ttbjm3TiVKXaWijU"
+
+    internal val A_POLL_CONTENT = MessagePollContent(
+            unstablePollCreationInfo = PollCreationInfo(
+                    question = PollQuestion(
+                            unstableQuestion = "What is your favourite coffee?"
+                    ),
+                    maxSelections = 1,
+                    answers = listOf(
+                            PollAnswer(
+                                    id = "5ef5f7b0-c9a1-49cf-a0b3-374729a43e76",
+                                    unstableAnswer = "Double Espresso"
+                            ),
+                            PollAnswer(
+                                    id = "ec1a4db0-46d8-4d7a-9bb6-d80724715938",
+                                    unstableAnswer = "Macchiato"
+                            ),
+                            PollAnswer(
+                                    id = "3677ca8e-061b-40ab-bffe-b22e4e88fcad",
+                                    unstableAnswer = "Iced Coffee"
+                            )
+                    )
+            )
+    )
+
+    internal val A_POLL_RESPONSE_CONTENT = MessagePollResponseContent(
+            unstableResponse = PollResponse(
+                    answers = listOf("5ef5f7b0-c9a1-49cf-a0b3-374729a43e76")
+            ),
+            relatesTo = RelationDefaultContent(
+                    type = RelationType.REFERENCE,
+                    eventId = AN_EVENT_ID
+            )
+    )
+
+    internal val A_POLL_END_CONTENT = MessageEndPollContent(
+            relatesTo = RelationDefaultContent(
+                    type = RelationType.REFERENCE,
+                    eventId = AN_EVENT_ID
+            )
+    )
+
+    internal val AN_INVALID_POLL_RESPONSE_CONTENT = MessagePollResponseContent(
+            unstableResponse = PollResponse(
+                    answers = listOf("fake-option-id")
+            ),
+            relatesTo = RelationDefaultContent(
+                    type = RelationType.REFERENCE,
+                    eventId = AN_EVENT_ID
+            )
+    )
+
+    internal val A_POLL_START_EVENT = Event(
+            type = EventType.POLL_START.first(),
+            eventId = AN_EVENT_ID,
+            originServerTs = 1652435922563,
+            senderId = A_USER_ID_1,
+            roomId = A_ROOM_ID,
+            content = A_POLL_CONTENT.toContent()
+    )
+
+    internal val A_POLL_RESPONSE_EVENT = Event(
+            type = EventType.POLL_RESPONSE.first(),
+            eventId = AN_EVENT_ID,
+            originServerTs = 1652435922563,
+            senderId = A_USER_ID_1,
+            roomId = A_ROOM_ID,
+            content = A_POLL_RESPONSE_CONTENT.toContent()
+    )
+
+    internal val A_POLL_END_EVENT = Event(
+            type = EventType.POLL_END.first(),
+            eventId = AN_EVENT_ID,
+            originServerTs = 1652435922563,
+            senderId = A_USER_ID_1,
+            roomId = A_ROOM_ID,
+            content = A_POLL_END_CONTENT.toContent()
+    )
+
+    internal val A_TIMELINE_EVENT = TimelineEvent(
+            root = A_POLL_START_EVENT,
+            localId = 1234,
+            eventId = AN_EVENT_ID,
+            displayIndex = 0,
+            senderInfo = SenderInfo(A_USER_ID_1, "A_USER_ID_1", true, null)
+    )
+
+    internal val A_POLL_RESPONSE_EVENT_WITH_A_WRONG_REFERENCE = A_POLL_RESPONSE_EVENT.copy(
+            content = A_POLL_RESPONSE_CONTENT
+                    .copy(
+                            relatesTo = RelationDefaultContent(
+                                    type = RelationType.REPLACE,
+                                    eventId = null
+                            )
+                    )
+                    .toContent()
+    )
+
+    internal val A_POLL_REPLACE_EVENT = A_POLL_START_EVENT.copy(
+            content = A_POLL_CONTENT
+                    .copy(
+                            relatesTo = RelationDefaultContent(
+                                    type = RelationType.REPLACE,
+                                    eventId = AN_EVENT_ID
+                            )
+                    )
+                    .toContent()
+    )
+
+    internal val A_BROKEN_POLL_REPLACE_EVENT = A_POLL_START_EVENT.copy(
+            content = A_POLL_CONTENT
+                    .copy(
+                            relatesTo = RelationDefaultContent(
+                                    type = RelationType.REPLACE,
+                                    eventId = null
+                            )
+                    )
+                    .toContent()
+    )
+
+    internal val A_POLL_REFERENCE_EVENT = A_POLL_START_EVENT.copy(
+            content = A_POLL_CONTENT
+                    .copy(
+                            relatesTo = RelationDefaultContent(
+                                    type = RelationType.REFERENCE,
+                                    eventId = AN_EVENT_ID
+                            )
+                    )
+                    .toContent()
+    )
+
+    internal val AN_INVALID_POLL_RESPONSE_EVENT = A_POLL_RESPONSE_EVENT.copy(
+            content = AN_INVALID_POLL_RESPONSE_CONTENT.toContent()
+    )
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRealm.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRealm.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c07f8e187363e934a79ca52e16ae224f1ecff85f
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRealm.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.test.fakes
+
+import io.mockk.every
+import io.mockk.mockk
+import io.realm.Realm
+import io.realm.RealmModel
+import io.realm.RealmQuery
+import io.realm.kotlin.where
+
+internal class FakeRealm {
+
+    val instance = mockk<Realm>(relaxed = true)
+
+    inline fun <reified T : RealmModel> givenWhereReturns(result: T?): RealmQuery<T> {
+        val queryResult = mockk<RealmQuery<T>>()
+        every { queryResult.findFirst() } returns result
+        every { instance.where<T>() } returns queryResult
+        return queryResult
+    }
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRequestExecutor.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRequestExecutor.kt
index 2f332a89a807be3d15d43842ac9e34b8a848fadb..ad20abf63c285763222fdd0c2a8cda7b64fe8fb1 100644
--- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRequestExecutor.kt
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRequestExecutor.kt
@@ -21,11 +21,13 @@ import org.matrix.android.sdk.internal.network.RequestExecutor
 
 internal class FakeRequestExecutor : RequestExecutor {
 
-    override suspend fun <DATA> executeRequest(globalErrorReceiver: GlobalErrorReceiver?,
-                                               canRetry: Boolean,
-                                               maxDelayBeforeRetry: Long,
-                                               maxRetriesCount: Int,
-                                               requestBlock: suspend () -> DATA): DATA {
+    override suspend fun <DATA> executeRequest(
+            globalErrorReceiver: GlobalErrorReceiver?,
+            canRetry: Boolean,
+            maxDelayBeforeRetry: Long,
+            maxRetriesCount: Int,
+            requestBlock: suspend () -> DATA
+    ): DATA {
         return requestBlock()
     }
 }