diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle
index 6ca21262de3e3055d1ab3d6fc4cee350a682ccb5..3d81c0dba9941d5751de9ccde4c35ecf403f9f79 100644
--- a/matrix-sdk-android/build.gradle
+++ b/matrix-sdk-android/build.gradle
@@ -9,7 +9,7 @@ buildscript {
         jcenter()
     }
     dependencies {
-        classpath "io.realm:realm-gradle-plugin:6.1.0"
+        classpath "io.realm:realm-gradle-plugin:10.0.0"
     }
 }
 
@@ -25,7 +25,7 @@ android {
         minSdkVersion 21
         targetSdkVersion 29
         versionCode 1
-        versionName "1.0.10"
+        versionName "1.0.11"
         // Multidex is useful for tests
         multiDexEnabled true
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -149,7 +149,7 @@ dependencies {
     implementation 'androidx.exifinterface:exifinterface:1.3.0'
 
     // Database
-    implementation 'com.github.Zhuinden:realm-monarchy:0.5.1'
+    implementation 'com.github.Zhuinden:realm-monarchy:0.7.1'
     kapt 'dk.ilios:realmfieldnameshelper:1.1.1'
 
     // Work
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 ec5477f97640a217c8bf57f2c47a44d07f6718df..103b638c397a6c52b5295c5faf84291986f02d1d 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
@@ -43,8 +43,8 @@ class ChangePasswordTest : InstrumentedTest {
         val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false))
 
         // Change password
-        commonTestHelper.doSync<Unit> {
-            session.changePassword(TestConstants.PASSWORD, NEW_PASSWORD, it)
+        commonTestHelper.runBlockingTest {
+            session.changePassword(TestConstants.PASSWORD, NEW_PASSWORD)
         }
 
         // Try to login with the previous password, it will fail
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 a6fbfd9b7abb91f9ed14631bdeef61bdb595329c..9996eef0a87eac74106c3544483af0008521206b 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
@@ -43,8 +43,8 @@ class DeactivateAccountTest : InstrumentedTest {
         val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false))
 
         // Deactivate the account
-        commonTestHelper.doSync<Unit> {
-            session.deactivateAccount(TestConstants.PASSWORD, false, it)
+        commonTestHelper.runBlockingTest {
+            session.deactivateAccount(TestConstants.PASSWORD, false)
         }
 
         // Try to login on the previous account, it will fail (M_USER_DEACTIVATED)
diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt
index cbe4cca8a3dcea03429f69d685ae53255a510287..0e7088a6a5a6dec08b83147f063adc5d73e8a0e8 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
@@ -40,6 +40,7 @@ import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withTimeout
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertNotNull
 import org.junit.Assert.assertTrue
@@ -343,6 +344,14 @@ class CommonTestHelper(context: Context) {
         await(latch, timeout)
     }
 
+    fun <T> runBlockingTest(timeout: Long = TestConstants.timeOutMillis, block: suspend () -> T): T {
+        return runBlocking {
+            withTimeout(timeout) {
+                block()
+            }
+        }
+    }
+
     // Transform a method with a MatrixCallback to a synchronous method
     inline fun <reified T> doSync(timeout: Long? = TestConstants.timeOutMillis, block: (MatrixCallback<T>) -> Unit): T {
         val lock = CountDownLatch(1)
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 1a9165ade4b9d2fd2f22798ff23373eca6ece49a..cbb22daf0f14ab7d4eaa089836408aaf5d929ecf 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
@@ -68,8 +68,8 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
         if (encryptedRoom) {
             val room = aliceSession.getRoom(roomId)!!
 
-            mTestHelper.doSync<Unit> {
-                room.enableEncryption(callback = it)
+            mTestHelper.runBlockingTest {
+                room.enableEncryption()
             }
         }
 
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 75c7ad4d53502ed04ec5fbf91aa11b5f1d5cff1a..a81f503e774e38c5467b7ae4f0e4662c616525d9 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
@@ -555,7 +555,7 @@ class SASTest : InstrumentedTest {
 
         mTestHelper.waitWithLatch {
             mTestHelper.retryPeriodicallyWithLatch(it) {
-                val prAlicePOV = aliceVerificationService.getExistingVerificationRequest(bobSession.myUserId)?.firstOrNull()
+                val prAlicePOV = aliceVerificationService.getExistingVerificationRequests(bobSession.myUserId).firstOrNull()
                 requestID = prAlicePOV?.transactionId
                 Log.v("TEST", "== alicePOV is $prAlicePOV")
                 prAlicePOV?.transactionId != null && prAlicePOV.localId == req.localId
@@ -566,7 +566,7 @@ class SASTest : InstrumentedTest {
 
         mTestHelper.waitWithLatch {
             mTestHelper.retryPeriodicallyWithLatch(it) {
-                val prBobPOV = bobVerificationService.getExistingVerificationRequest(aliceSession.myUserId)?.firstOrNull()
+                val prBobPOV = bobVerificationService.getExistingVerificationRequests(aliceSession.myUserId).firstOrNull()
                 Log.v("TEST", "== prBobPOV is $prBobPOV")
                 prBobPOV?.transactionId == requestID
             }
@@ -581,7 +581,7 @@ class SASTest : InstrumentedTest {
         // wait for alice to get the ready
         mTestHelper.waitWithLatch {
             mTestHelper.retryPeriodicallyWithLatch(it) {
-                val prAlicePOV = aliceVerificationService.getExistingVerificationRequest(bobSession.myUserId)?.firstOrNull()
+                val prAlicePOV = aliceVerificationService.getExistingVerificationRequests(bobSession.myUserId).firstOrNull()
                 Log.v("TEST", "== prAlicePOV is $prAlicePOV")
                 prAlicePOV?.transactionId == requestID && prAlicePOV?.isReady != null
             }
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 7db159cd0b25a0a8dad3ea1ab48373b3abe47097..ae300c936d89acf552e9ee3db5aad25b21d3c695 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
@@ -71,38 +71,27 @@ class SearchMessagesTest : InstrumentedTest {
             commonTestHelper.await(lock)
 
             lock = CountDownLatch(1)
-            aliceSession
-                    .searchService()
-                    .search(
-                            searchTerm = "lore",
-                            limit = 10,
-                            includeProfile = true,
-                            afterLimit = 0,
-                            beforeLimit = 10,
-                            orderByRecent = true,
-                            nextBatch = null,
-                            roomId = aliceRoomId,
-                            callback = object : MatrixCallback<SearchResult> {
-                                override fun onSuccess(data: SearchResult) {
-                                    super.onSuccess(data)
-                                    assertTrue(data.results?.size == 2)
-                                    assertTrue(
-                                            data.results
-                                                    ?.all {
-                                                        (it.event.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse()
-                                                    }.orFalse()
-                                    )
-                                    lock.countDown()
-                                }
-
-                                override fun onFailure(failure: Throwable) {
-                                    super.onFailure(failure)
-                                    fail(failure.localizedMessage)
-                                    lock.countDown()
-                                }
-                            }
-                    )
-            lock.await(TestConstants.timeOutMillis, TimeUnit.MILLISECONDS)
+            val data = commonTestHelper.runBlockingTest {
+                aliceSession
+                        .searchService()
+                        .search(
+                                searchTerm = "lore",
+                                limit = 10,
+                                includeProfile = true,
+                                afterLimit = 0,
+                                beforeLimit = 10,
+                                orderByRecent = true,
+                                nextBatch = null,
+                                roomId = aliceRoomId
+                        )
+            }
+            assertTrue(data.results?.size == 2)
+            assertTrue(
+                    data.results
+                            ?.all {
+                                (it.event.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse()
+                            }.orFalse()
+            )
 
             aliceTimeline.removeAllListeners()
             cryptoTestData.cleanUp(commonTestHelper)
diff --git a/matrix-sdk-android/src/debug/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt b/matrix-sdk-android/src/debug/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt
index 5c03e8a855039ae0b6c6d258b2d79679f2964a67..630f6f1e29903ccf110d9982fa6cf8d565b1e856 100644
--- a/matrix-sdk-android/src/debug/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt
+++ b/matrix-sdk-android/src/debug/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt
@@ -66,9 +66,9 @@ class FormattedJsonHttpLogger : HttpLoggingInterceptor.Logger {
     }
 
     private fun logJson(formattedJson: String) {
-        val arr = formattedJson.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
-        for (s in arr) {
-            Timber.v(s)
-        }
+        formattedJson
+                .lines()
+                .dropLastWhile { it.isEmpty() }
+                .forEach { Timber.v(it) }
     }
 }
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 645fb55bb98905c729e6b356d8dc8a38f4f32487..48705ee7b7dbfbb6c602dca5409ea433bfb018df 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
@@ -27,7 +27,7 @@ interface LoginWizard {
      * @param password the password field
      * @param deviceName the initial device name
      * @param callback  the matrix callback on which you'll receive the result of authentication.
-     * @return return a [Cancelable]
+     * @return a [Cancelable]
      */
     fun login(login: String,
               password: String,
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 a17e65b8e0c8edf64fa6ba9916e8ec85ebf46db4..e264843ea49654ce151cb29b5529a12e69db8113 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
@@ -22,3 +22,8 @@ fun CharSequence.ensurePrefix(prefix: CharSequence): CharSequence {
         else               -> "$prefix$this"
     }
 }
+
+/**
+ * Append a new line and then the provided string
+ */
+fun StringBuilder.appendNl(str: String) = append("\n").append(str)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushRuleService.kt
index 880a7be9ac863ed3abe8cd51abc87e902ec11419..4da1662681e08c5dd6a13ffdca049509796adc63 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushRuleService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/PushRuleService.kt
@@ -15,11 +15,9 @@
  */
 package org.matrix.android.sdk.api.pushrules
 
-import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.pushrules.rest.PushRule
 import org.matrix.android.sdk.api.pushrules.rest.RuleSet
 import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.util.Cancelable
 
 interface PushRuleService {
     /**
@@ -29,13 +27,13 @@ interface PushRuleService {
 
     fun getPushRules(scope: String = RuleScope.GLOBAL): RuleSet
 
-    fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback<Unit>): Cancelable
+    suspend fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean)
 
-    fun addPushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
+    suspend fun addPushRule(kind: RuleKind, pushRule: PushRule)
 
-    fun updatePushRuleActions(kind: RuleKind, oldPushRule: PushRule, newPushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
+    suspend fun updatePushRuleActions(kind: RuleKind, oldPushRule: PushRule, newPushRule: PushRule)
 
-    fun removePushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable
+    suspend fun removePushRule(kind: RuleKind, pushRule: PushRule)
 
     fun addPushRuleListener(listener: PushRuleListener)
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt
index 4e24a17047ea606f5e91cd7be738935e7ac9ac36..19549a338ed124805f74cd706f7ee3cd4258bd11 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/raw/RawService.kt
@@ -16,9 +16,6 @@
 
 package org.matrix.android.sdk.api.raw
 
-import org.matrix.android.sdk.api.MatrixCallback
-import org.matrix.android.sdk.api.util.Cancelable
-
 /**
  * Useful methods to fetch raw data from the server. The access token will not be used to fetched the data
  */
@@ -26,17 +23,15 @@ interface RawService {
     /**
      * Get a URL, either from cache or from the remote server, depending on the cache strategy
      */
-    fun getUrl(url: String,
-               rawCacheStrategy: RawCacheStrategy,
-               matrixCallback: MatrixCallback<String>): Cancelable
+    suspend fun getUrl(url: String, rawCacheStrategy: RawCacheStrategy): String
 
     /**
      * Specific case for the well-known file. Cache validity is 8 hours
      */
-    fun getWellknown(userId: String, matrixCallback: MatrixCallback<String>): Cancelable
+    suspend fun getWellknown(userId: String): String
 
     /**
      * Clear all the cache data
      */
-    fun clearCache(matrixCallback: MatrixCallback<Unit>): Cancelable
+    suspend fun clearCache()
 }
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 b05f0036b2150bab5af7ec658f080fe75da878e9..8915202f355d6d38cb2a6fee3684f721f9c4c282 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
@@ -16,9 +16,6 @@
 
 package org.matrix.android.sdk.api.session.account
 
-import org.matrix.android.sdk.api.MatrixCallback
-import org.matrix.android.sdk.api.util.Cancelable
-
 /**
  * This interface defines methods to manage the account. It's implemented at the session level.
  */
@@ -28,7 +25,7 @@ interface AccountService {
      * @param password Current password.
      * @param newPassword New password
      */
-    fun changePassword(password: String, newPassword: String, callback: MatrixCallback<Unit>): Cancelable
+    suspend fun changePassword(password: String, newPassword: String)
 
     /**
      * Deactivate the account.
@@ -46,5 +43,5 @@ interface AccountService {
      * @param eraseAllData set to true to forget all messages that have been sent. Warning: this will cause future users to see
      * an incomplete view of conversations
      */
-    fun deactivateAccount(password: String, eraseAllData: Boolean, callback: MatrixCallback<Unit>): Cancelable
+    suspend fun deactivateAccount(password: String, eraseAllData: Boolean)
 }
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 65c6a1f1f7d0cda5572a2088f0cc37712443b10e..2413786ea90cd85f7d0fef382670c9dbbfcf4e5c 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
@@ -41,7 +41,7 @@ interface VerificationService {
 
     fun getExistingTransaction(otherUserId: String, tid: String): VerificationTransaction?
 
-    fun getExistingVerificationRequest(otherUserId: String): List<PendingVerificationRequest>?
+    fun getExistingVerificationRequests(otherUserId: String): List<PendingVerificationRequest>
 
     fun getExistingVerificationRequest(otherUserId: String, tid: String?): PendingVerificationRequest?
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt
index 82dea81a5b22caa2202dd0f20908e8d629516160..0a7f3ff09f1dff8731c2de38cb94cc77080096a0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt
@@ -56,6 +56,7 @@ object EventType {
     const val STATE_ROOM_RELATED_GROUPS = "m.room.related_groups"
     const val STATE_ROOM_PINNED_EVENT = "m.room.pinned_events"
     const val STATE_ROOM_ENCRYPTION = "m.room.encryption"
+    const val STATE_ROOM_SERVER_ACL = "m.room.server_acl"
 
     // Call Events
     const val CALL_INVITE = "m.call.invite"
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/Group.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/Group.kt
index a4186b5a324e1a6c1590025cdcde7dfcf65c46bd..25c69e5025cf306c988d7fbcf24830f61c479388 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/Group.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/group/Group.kt
@@ -16,9 +16,6 @@
 
 package org.matrix.android.sdk.api.session.group
 
-import org.matrix.android.sdk.api.MatrixCallback
-import org.matrix.android.sdk.api.util.Cancelable
-
 /**
  * This interface defines methods to interact within a group.
  */
@@ -28,8 +25,7 @@ interface Group {
     /**
      * This methods allows you to refresh data about this group. It will be reflected on the GroupSummary.
      * The SDK also takes care of refreshing group data every hour.
-     * @param callback : the matrix callback to be notified of success or failure
      * @return a Cancelable to be able to cancel requests.
      */
-    fun fetchGroupData(callback: MatrixCallback<Unit>): Cancelable
+    suspend fun fetchGroupData()
 }
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 537104a084ed9c792f094aa4fb39ce4cc76c0539..aedb81373585412377705b40aec3ee1d115311fd 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
@@ -92,9 +92,29 @@ interface IdentityService {
 
     /**
      * Search MatrixId of users providing email and phone numbers
+     * Note the the user consent has to be set to true, or it will throw a UserConsentNotProvided failure
+     * Application has to explicitly ask for the user consent, and the answer can be stored using [setUserConsent]
+     * Please see https://support.google.com/googleplay/android-developer/answer/9888076?hl=en for more details.
      */
     fun lookUp(threePids: List<ThreePid>, callback: MatrixCallback<List<FoundThreePid>>): Cancelable
 
+    /**
+     * Return the current user consent for the current identity server, which has been stored using [setUserConsent].
+     * If [setUserConsent] has not been called, the returned value will be false.
+     * Note that if the identity server is changed, the user consent is reset to false.
+     * @return the value stored using [setUserConsent] or false if [setUserConsent] has never been called, or if the identity server
+     *         has been changed
+     */
+    fun getUserConsent(): Boolean
+
+    /**
+     * Set the user consent to the provided value. Application MUST explicitly ask for the user consent to send their private data
+     * (email and phone numbers) to the identity server.
+     * Please see https://support.google.com/googleplay/android-developer/answer/9888076?hl=en for more details.
+     * @param newValue true if the user explicitly give their consent, false if the user wants to revoke their consent.
+     */
+    fun setUserConsent(newValue: Boolean)
+
     /**
      * Get the status of the current user's threePid
      * A lookup will be performed, but also pending binding state will be restored
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityServiceError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityServiceError.kt
index 72bb72cc2c473578c059e00fda1a8a915cab5a89..42fdb976431e174b2dff203f3d5725be48b44e06 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityServiceError.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityServiceError.kt
@@ -24,6 +24,7 @@ sealed class IdentityServiceError : Failure.FeatureFailure() {
     object NoIdentityServerConfigured : IdentityServiceError()
     object TermsNotSignedException : IdentityServiceError()
     object BulkLookupSha256NotSupported : IdentityServiceError()
+    object UserConsentNotProvided : IdentityServiceError()
     object BindingError : IdentityServiceError()
     object NoCurrentBindingError : IdentityServiceError()
 }
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 7f264c6228c222cb2e8df9061efa318e9ee7c316..5e9f3e1eb93732e70e311e0b9eaf719fe33323d6 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
@@ -17,6 +17,7 @@
 package org.matrix.android.sdk.api.session.permalinks
 
 import android.text.Spannable
+import org.matrix.android.sdk.api.MatrixPatterns
 
 /**
  *  MatrixLinkify take a piece of text and turns all of the
@@ -35,7 +36,7 @@ object MatrixLinkify {
          * I disable it because it mess up with pills, and even with pills, it does not work correctly:
          * The url is not correct. Ex: for @user:matrix.org, the url will be @user:matrix.org, instead of a matrix.to
          */
-        /*
+
         // sanity checks
         if (spannable.isEmpty()) {
             return false
@@ -48,14 +49,21 @@ object MatrixLinkify {
                 val startPos = match.range.first
                 if (startPos == 0 || text[startPos - 1] != '/') {
                     val endPos = match.range.last + 1
-                    val url = text.substring(match.range)
+                    var url = text.substring(match.range)
+                    if (MatrixPatterns.isUserId(url)
+                            || MatrixPatterns.isRoomAlias(url)
+                            || MatrixPatterns.isRoomId(url)
+                            || MatrixPatterns.isGroupId(url)
+                            || MatrixPatterns.isEventId(url)) {
+                        url = PermalinkService.MATRIX_TO_URL_BASE  + url
+                    }
                     val span = MatrixPermalinkSpan(url, callback)
                     spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
                 }
             }
         }
         return hasMatch
-         */
-        return false
+
+//        return false
     }
 }
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 dc47c81a5f50b4c24a843bf70102dd21c3c36ced..347a3bb5313c95cfccedd1f4a7a946a584e59f07 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
@@ -44,13 +44,12 @@ object PermalinkParser {
         if (fragment.isNullOrEmpty()) {
             return PermalinkData.FallbackLink(uri)
         }
-        val indexOfQuery = fragment.indexOf("?")
-        val safeFragment = if (indexOfQuery != -1) fragment.substring(0, indexOfQuery) else fragment
+        val safeFragment = fragment.substringBefore('?')
         val viaQueryParameters = fragment.getViaParameters()
 
         // we are limiting to 2 params
         val params = safeFragment
-                .split(MatrixPatterns.SEP_REGEX.toRegex())
+                .split(MatrixPatterns.SEP_REGEX)
                 .filter { it.isNotEmpty() }
                 .take(2)
 
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 b772225f5197a2c134236a18d8617f3354944705..f30037e5c21b04c512fb710fffae46db4d4ef3dc 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
@@ -19,6 +19,7 @@ package org.matrix.android.sdk.api.session.room
 import androidx.lifecycle.LiveData
 import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
+import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
 import org.matrix.android.sdk.api.util.Cancelable
@@ -141,4 +142,20 @@ interface RoomService {
      *  - the power level of the users are not taken into account. Normally in a DM, the 2 members are admins of the room
      */
     fun getExistingDirectRoomWithUser(otherUserId: String): String?
+
+    /**
+     * Get a room member for the tuple {userId,roomId}
+     * @param userId the userId to look for.
+     * @param roomId the roomId to look for.
+     * @return the room member or null
+     */
+    fun getRoomMember(userId: String, roomId: String): RoomMemberSummary?
+
+    /**
+     * Observe a live room member for the tuple {userId,roomId}
+     * @param userId the userId to look for.
+     * @param roomId the roomId to look for.
+     * @return a LiveData of the optional found room member
+     */
+    fun getRoomMemberLive(userId: String, roomId: String): LiveData<Optional<RoomMemberSummary>>
 }
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 e7e6bacc2206299e064719ccb3d6bd53073c8874..1251fd985732308b13c86872c7b549660d4d5868 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
@@ -16,7 +16,6 @@
 
 package org.matrix.android.sdk.api.session.room.crypto
 
-import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
 
 interface RoomCryptoService {
@@ -30,6 +29,5 @@ interface RoomCryptoService {
     /**
      * Enable encryption of the room
      */
-    fun enableEncryption(algorithm: String = MXCRYPTO_ALGORITHM_MEGOLM,
-                         callback: MatrixCallback<Unit>)
+    suspend fun enableEncryption(algorithm: String = MXCRYPTO_ALGORITHM_MEGOLM)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt
index b0df2963f780820a953382c7d76f5e8b31afc916..b4e2dc645c55692b997b2517e6cf0b61d7cdaaf7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/failure/CreateRoomFailure.kt
@@ -22,4 +22,9 @@ import org.matrix.android.sdk.api.failure.MatrixError
 sealed class CreateRoomFailure : Failure.FeatureFailure() {
     object CreatedWithTimeout : CreateRoomFailure()
     data class CreatedWithFederationFailure(val matrixError: MatrixError) : CreateRoomFailure()
+    sealed class RoomAliasError : CreateRoomFailure() {
+        object AliasEmpty : RoomAliasError()
+        object AliasNotAvailable : RoomAliasError()
+        object AliasInvalid : RoomAliasError()
+    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomServerAclContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomServerAclContent.kt
new file mode 100644
index 0000000000000000000000000000000000000000..92078054b75e5bbcf4498d7845b1a0fff5585e3e
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomServerAclContent.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.room.model
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+/**
+ * Class representing the EventType.STATE_ROOM_SERVER_ACL state event content
+ * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#m-room-server-acl
+ */
+@JsonClass(generateAdapter = true)
+data class RoomServerAclContent(
+        /**
+         * True to allow server names that are IP address literals. False to deny.
+         * Defaults to true if missing or otherwise not a boolean.
+         * This is strongly recommended to be set to false as servers running with IP literal names are strongly
+         * discouraged in order to require legitimate homeservers to be backed by a valid registered domain name.
+         */
+        @Json(name = "allow_ip_literals")
+        val allowIpLiterals: Boolean = true,
+
+        /**
+         * The server names to allow in the room, excluding any port information. Wildcards may be used to cover
+         * a wider range of hosts, where * matches zero or more characters and ? matches exactly one character.
+         *
+         * This defaults to an empty list when not provided, effectively disallowing every server.
+         */
+        @Json(name = "allow")
+        val allowList: List<String> = emptyList(),
+
+        /**
+         * The server names to disallow in the room, excluding any port information. Wildcards may be used to cover
+         * a wider range of hosts, where * matches zero or more characters and ? matches exactly one character.
+         *
+         * This defaults to an empty list when not provided.
+         */
+        @Json(name = "deny")
+        val denyList: List<String> = emptyList()
+
+) {
+    companion object {
+        const val ALL = "*"
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt
index 892a86575184520488ed842920c943f0f33d5932..80e3741a0c90e4ed721e4f452ff59807827e2b0b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt
@@ -94,7 +94,22 @@ class CreateRoomParams {
      * The server will clobber the following keys: creator.
      * Future versions of the specification may allow the server to clobber other keys.
      */
-    var creationContent: Any? = null
+    val creationContent = mutableMapOf<String, Any>()
+
+    /**
+     * Set to true to disable federation of this room.
+     * Default: false
+     */
+    var disableFederation = false
+        set(value) {
+            field = value
+            if (value) {
+                creationContent[CREATION_CONTENT_KEY_M_FEDERATE] = false
+            } else {
+                // This is the default value, we remove the field
+                creationContent.remove(CREATION_CONTENT_KEY_M_FEDERATE)
+            }
+        }
 
     /**
      * The power level content to override in the default power level event
@@ -120,4 +135,8 @@ class CreateRoomParams {
     fun enableEncryption() {
         algorithm = MXCRYPTO_ALGORITHM_MEGOLM
     }
+
+    companion object {
+        private const val CREATION_CONTENT_KEY_M_FEDERATE = "m.federate"
+    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/notification/RoomPushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/notification/RoomPushRuleService.kt
index 32d6033578dc49832dc8f611b0985e62674c40b0..eb822c68acf2b339607b1cb5631695dcdb7168a8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/notification/RoomPushRuleService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/notification/RoomPushRuleService.kt
@@ -17,12 +17,10 @@
 package org.matrix.android.sdk.api.session.room.notification
 
 import androidx.lifecycle.LiveData
-import org.matrix.android.sdk.api.MatrixCallback
-import org.matrix.android.sdk.api.util.Cancelable
 
 interface RoomPushRuleService {
 
     fun getLiveRoomNotificationState(): LiveData<RoomNotificationState>
 
-    fun setRoomNotificationState(roomNotificationState: RoomNotificationState, matrixCallback: MatrixCallback<Unit>): Cancelable
+    suspend fun setRoomNotificationState(roomNotificationState: RoomNotificationState)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/reporting/ReportingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/reporting/ReportingService.kt
index 0ccdfd1d3c877c30143a60a541d86a2d3dd8ed66..a444e2346e6c2b7eac088e555620a87086660c46 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/reporting/ReportingService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/reporting/ReportingService.kt
@@ -16,9 +16,6 @@
 
 package org.matrix.android.sdk.api.session.room.reporting
 
-import org.matrix.android.sdk.api.MatrixCallback
-import org.matrix.android.sdk.api.util.Cancelable
-
 /**
  * This interface defines methods to report content of an event.
  */
@@ -28,5 +25,5 @@ interface ReportingService {
      * Report content
      * Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-rooms-roomid-report-eventid
      */
-    fun reportContent(eventId: String, score: Int, reason: String, callback: MatrixCallback<Unit>): Cancelable
+    suspend fun reportContent(eventId: String, score: Int, reason: String)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/DraftService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/DraftService.kt
index 116a60e323946e375b31bd16dac95110399795a3..a9481d71a2002ce3873cf840e5999681fafaa0bd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/DraftService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/DraftService.kt
@@ -17,8 +17,6 @@
 package org.matrix.android.sdk.api.session.room.send
 
 import androidx.lifecycle.LiveData
-import org.matrix.android.sdk.api.MatrixCallback
-import org.matrix.android.sdk.api.util.Cancelable
 import org.matrix.android.sdk.api.util.Optional
 
 interface DraftService {
@@ -26,12 +24,12 @@ interface DraftService {
     /**
      * Save or update a draft to the room
      */
-    fun saveDraft(draft: UserDraft, callback: MatrixCallback<Unit>): Cancelable
+    suspend fun saveDraft(draft: UserDraft)
 
     /**
      * Delete the last draft, basically just after sending the message
      */
-    fun deleteDraft(callback: MatrixCallback<Unit>): Cancelable
+    suspend fun deleteDraft()
 
     /**
      * Return the current draft or null
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/tags/TagsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/tags/TagsService.kt
index 3278c640de83ea96b4c259636d8b28f7bfea61b4..69fde61f90e44e142db07663d91ecfb04c289248 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/tags/TagsService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/tags/TagsService.kt
@@ -16,9 +16,6 @@
 
 package org.matrix.android.sdk.api.session.room.tags
 
-import org.matrix.android.sdk.api.MatrixCallback
-import org.matrix.android.sdk.api.util.Cancelable
-
 /**
  * This interface defines methods to handle tags of a room. It's implemented at the room level.
  */
@@ -26,10 +23,10 @@ interface TagsService {
     /**
      * Add a tag to a room
      */
-    fun addTag(tag: String, order: Double?, callback: MatrixCallback<Unit>): Cancelable
+    suspend fun addTag(tag: String, order: Double?)
 
     /**
      * Remove tag from a room
      */
-    fun deleteTag(tag: String, callback: MatrixCallback<Unit>): Cancelable
+    suspend fun deleteTag(tag: String)
 }
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 ef2eec433f0d0a0597d54a81ed2d4aa1799d8acc..bc1c9e57694ad23d2e1f7fd2b085629178dce161 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
@@ -16,9 +16,6 @@
 
 package org.matrix.android.sdk.api.session.search
 
-import org.matrix.android.sdk.api.MatrixCallback
-import org.matrix.android.sdk.api.util.Cancelable
-
 /**
  * This interface defines methods to search messages in rooms.
  */
@@ -35,15 +32,13 @@ interface SearchService {
      * @param beforeLimit how many events before the result are returned.
      * @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.
-     * @param callback Callback to get the search result
      */
-    fun search(searchTerm: String,
-               roomId: String,
-               nextBatch: String?,
-               orderByRecent: Boolean,
-               limit: Int,
-               beforeLimit: Int,
-               afterLimit: Int,
-               includeProfile: Boolean,
-               callback: MatrixCallback<SearchResult>): Cancelable
+    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/session/user/UserService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/UserService.kt
index 2cfc4b731f1377ec0149c500c7179ffbbece463a..ab85f979bf6ca591a31031ea1b5b91b2103074ff 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/UserService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/user/UserService.kt
@@ -35,6 +35,11 @@ interface UserService {
      */
     fun getUser(userId: String): User?
 
+    /**
+     * Try to resolve user from known users, or using profile api
+     */
+    fun resolveUser(userId: String, callback: MatrixCallback<User>)
+
     /**
      * Search list of users on server directory.
      * @param search the searched term
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 a8580bab8e9b8e8b12380a2adc43a84a9152f6d6..a786ebd4b2baaa7d7efa738d47f4dea307623694 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
@@ -123,6 +123,7 @@ internal abstract class CryptoModule {
                     }
                     .name("crypto_store.realm")
                     .modules(RealmCryptoStoreModule())
+                    .allowWritesOnUiThread(true)
                     .schemaVersion(RealmCryptoStoreMigration.CRYPTO_STORE_SCHEMA_VERSION)
                     .migration(realmCryptoStoreMigration)
                     .build()
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 d3a3fd9fbdc532652178775cb5ba8ef4fc58056d..ebd809f7774ee2375a61e4677a73a662cbf6f92d 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
@@ -767,9 +767,9 @@ internal class DefaultCryptoService @Inject constructor(
      */
     private fun onRoomKeyEvent(event: Event) {
         val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>() ?: return
-        Timber.v("## CRYPTO | GOSSIP onRoomKeyEvent() : type<${event.getClearType()}> , sessionId<${roomKeyContent.sessionId}>")
+        Timber.i("## CRYPTO | onRoomKeyEvent() from: ${event.senderId} type<${event.getClearType()}> , sessionId<${roomKeyContent.sessionId}>")
         if (roomKeyContent.roomId.isNullOrEmpty() || roomKeyContent.algorithm.isNullOrEmpty()) {
-            Timber.e("## CRYPTO | GOSSIP onRoomKeyEvent() : missing fields")
+            Timber.e("## CRYPTO | onRoomKeyEvent() : missing fields")
             return
         }
         val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(roomKeyContent.roomId, roomKeyContent.algorithm)
@@ -782,20 +782,20 @@ internal class DefaultCryptoService @Inject constructor(
 
     private fun onKeyWithHeldReceived(event: Event) {
         val withHeldContent = event.getClearContent().toModel<RoomKeyWithHeldContent>() ?: return Unit.also {
-            Timber.e("## CRYPTO | Malformed onKeyWithHeldReceived() : missing fields")
+            Timber.i("## CRYPTO | Malformed onKeyWithHeldReceived() : missing fields")
         }
-        Timber.d("## CRYPTO | onKeyWithHeldReceived() received : content <$withHeldContent>")
+        Timber.i("## CRYPTO | onKeyWithHeldReceived() received from:${event.senderId}, content <$withHeldContent>")
         val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(withHeldContent.roomId, withHeldContent.algorithm)
         if (alg is IMXWithHeldExtension) {
             alg.onRoomKeyWithHeldEvent(withHeldContent)
         } else {
-            Timber.e("## CRYPTO | onKeyWithHeldReceived() : Unable to handle WithHeldContent for ${withHeldContent.algorithm}")
+            Timber.e("## CRYPTO | onKeyWithHeldReceived() from:${event.senderId}: Unable to handle WithHeldContent for ${withHeldContent.algorithm}")
             return
         }
     }
 
     private fun onSecretSendReceived(event: Event) {
-        Timber.i("## CRYPTO | GOSSIP onSecretSend() : onSecretSendReceived ${event.content?.get("sender_key")}")
+        Timber.i("## CRYPTO | GOSSIP onSecretSend() from ${event.senderId} : onSecretSendReceived ${event.content?.get("sender_key")}")
         if (!event.isEncrypted()) {
             // secret send messages must be encrypted
             Timber.e("## CRYPTO | GOSSIP onSecretSend() :Received unencrypted secret send event")
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 38488f1ca7c6a4938198f7de568eb107c5078815..92b77288909132f34d5b37724f2c937a7c7689ad 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
@@ -119,7 +119,7 @@ internal class EventDecryptor @Inject constructor(
                                             markOlmSessionForUnwedging(event.senderId ?: "", it)
                                         }
                                         ?: run {
-                                            Timber.v("## CRYPTO | markOlmSessionForUnwedging() : Failed to find sender crypto device")
+                                            Timber.i("## CRYPTO | internalDecryptEvent() : Failed to find sender crypto device for unwedging")
                                         }
                             }
                         }
@@ -137,16 +137,18 @@ internal class EventDecryptor @Inject constructor(
         val lastForcedDate = lastNewSessionForcedDates.getObject(senderId, deviceKey) ?: 0
         val now = System.currentTimeMillis()
         if (now - lastForcedDate < DefaultCryptoService.CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
-            Timber.d("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
+            Timber.w("## CRYPTO | markOlmSessionForUnwedging: New session already forced with device at $lastForcedDate. Not forcing another")
             return
         }
 
-        Timber.d("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
+        Timber.i("## CRYPTO | markOlmSessionForUnwedging from $senderId:${deviceInfo.deviceId}")
         lastNewSessionForcedDates.setObject(senderId, deviceKey, now)
 
         // offload this from crypto thread (?)
         cryptoCoroutineScope.launch(coroutineDispatchers.computation) {
-            ensureOlmSessionsForDevicesAction.handle(mapOf(senderId to listOf(deviceInfo)), force = true)
+            val ensured = ensureOlmSessionsForDevicesAction.handle(mapOf(senderId to listOf(deviceInfo)), force = true)
+
+            Timber.i("## CRYPTO | markOlmSessionForUnwedging() : ensureOlmSessionsForDevicesAction isEmpty:${ensured.isEmpty}")
 
             // Now send a blank message on that session so the other side knows about it.
             // (The keyshare request is sent in the clear so that won't do)
@@ -159,10 +161,14 @@ internal class EventDecryptor @Inject constructor(
             val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
             val sendToDeviceMap = MXUsersDevicesMap<Any>()
             sendToDeviceMap.setObject(senderId, deviceInfo.deviceId, encodedPayload)
-            Timber.v("## CRYPTO | markOlmSessionForUnwedging() : sending to $senderId:${deviceInfo.deviceId}")
+            Timber.i("## CRYPTO | markOlmSessionForUnwedging() : sending dummy to $senderId:${deviceInfo.deviceId}")
             withContext(coroutineDispatchers.io) {
                 val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
-                sendToDeviceTask.execute(sendToDeviceParams)
+                try {
+                    sendToDeviceTask.execute(sendToDeviceParams)
+                } catch (failure: Throwable) {
+                    Timber.e(failure, "## CRYPTO | markOlmSessionForUnwedging() : failed to send dummy to $senderId:${deviceInfo.deviceId}")
+                }
             }
         }
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt
index 97ae0b9d836379116726154860e3219890b2ace8..4f94a27bbd9ed7814309bbcba711e94cdbe96c58 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt
@@ -54,6 +54,7 @@ internal class IncomingGossipingRequestManager @Inject constructor(
         private val cryptoCoroutineScope: CoroutineScope) {
 
     private val executor = Executors.newSingleThreadExecutor()
+
     // list of IncomingRoomKeyRequests/IncomingRoomKeyRequestCancellations
     // we received in the current sync.
     private val receivedGossipingRequests = ArrayList<IncomingShareRequestCommon>()
@@ -103,11 +104,11 @@ internal class IncomingGossipingRequestManager @Inject constructor(
      * @param event the announcement event.
      */
     fun onGossipingRequestEvent(event: Event) {
-        Timber.v("## CRYPTO | GOSSIP onGossipingRequestEvent type ${event.type} from user ${event.senderId}")
         val roomKeyShare = event.getClearContent().toModel<GossipingDefaultContent>()
+        Timber.i("## CRYPTO | GOSSIP onGossipingRequestEvent received type ${event.type} from user:${event.senderId}, content:$roomKeyShare")
         // val ageLocalTs = event.unsignedData?.age?.let { System.currentTimeMillis() - it }
         when (roomKeyShare?.action) {
-            GossipingToDeviceObject.ACTION_SHARE_REQUEST      -> {
+            GossipingToDeviceObject.ACTION_SHARE_REQUEST -> {
                 if (event.getClearType() == EventType.REQUEST_SECRET) {
                     IncomingSecretShareRequest.fromEvent(event)?.let {
                         if (event.senderId == credentials.userId && it.deviceId == credentials.deviceId) {
@@ -324,7 +325,7 @@ internal class IncomingGossipingRequestManager @Inject constructor(
         val isDeviceLocallyVerified = cryptoStore.getUserDevice(userId, deviceId)?.trustLevel?.isLocallyVerified()
 
         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
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 1a4d1136c85cb4a39ae3ee3ffdb26206a76ebac4..c952602d93f40517e352abbcda76bb1129579b51 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
@@ -760,7 +760,7 @@ internal class MXOlmDevice @Inject constructor(
                 return session
             }
         } else {
-            Timber.v("## getInboundGroupSession() : Cannot retrieve inbound group session $sessionId")
+            Timber.w("## getInboundGroupSession() : Cannot retrieve inbound group session $sessionId")
             throw MXCryptoError.Base(MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID, MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_REASON)
         }
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipWorker.kt
index f0a341397807fd7b89e813afd7ef003d9bd3d9b5..bcaa16f35637b524da116d45ab5052e2504200f6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SendGossipWorker.kt
@@ -100,7 +100,7 @@ internal class SendGossipWorker(context: Context,
                         requestId = params.requestId,
                         state = GossipingRequestState.FAILED_TO_ACCEPTED
                 )
-                Timber.e("no session with this device, probably because there were no one-time keys.")
+                Timber.e("no session with this device $requestingDeviceId, probably because there were no one-time keys.")
             }
         }
 
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 b05f2cd592e7d23eaefba319976c2f9e90a85fa3..95b99c54e86d7ee008ca5377db252de640f0057f 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
@@ -69,7 +69,7 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(
         //
         // That should eventually resolve itself, but it's poor form.
 
-        Timber.v("## CRYPTO | claimOneTimeKeysForUsersDevices() : $usersDevicesToClaim")
+        Timber.i("## CRYPTO | claimOneTimeKeysForUsersDevices() : $usersDevicesToClaim")
 
         val claimParams = ClaimOneTimeKeysForUsersDeviceTask.Params(usersDevicesToClaim)
         val oneTimeKeys = oneTimeKeysForUsersDeviceTask.execute(claimParams)
@@ -90,7 +90,7 @@ internal class EnsureOlmSessionsForDevicesAction @Inject constructor(
                             oneTimeKey = key
                         }
                         if (oneTimeKey == null) {
-                            Timber.v("## CRYPTO | ensureOlmSessionsForDevices() : No one-time keys " + oneTimeKeyAlgorithm
+                            Timber.w("## CRYPTO | ensureOlmSessionsForDevices() : No one-time keys " + oneTimeKeyAlgorithm
                                     + " for device " + userId + " : " + deviceId)
                             continue
                         }
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 e0116fae1c862773c184bedc7c2c2737ffc70a36..787d16defc718ebc2b45c24f99181f8ec870440b 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
@@ -243,8 +243,7 @@ internal class MXMegolmDecryption(private val userId: String,
             return
         }
         if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
-            Timber.v("## CRYPTO | onRoomKeyEvent(), forward adding key : roomId ${roomKeyContent.roomId}" +
-                    " sessionId ${roomKeyContent.sessionId} sessionKey ${roomKeyContent.sessionKey}")
+            Timber.i("## CRYPTO | onRoomKeyEvent(), forward adding key : ${roomKeyContent.roomId}|${roomKeyContent.sessionId}")
             val forwardedRoomKeyContent = event.getClearContent().toModel<ForwardedRoomKeyContent>()
                     ?: return
 
@@ -273,9 +272,7 @@ internal class MXMegolmDecryption(private val userId: String,
 
             keysClaimed["ed25519"] = forwardedRoomKeyContent.senderClaimedEd25519Key
         } else {
-            Timber.v("## CRYPTO | onRoomKeyEvent(), Adding key : roomId " + roomKeyContent.roomId + " sessionId " + roomKeyContent.sessionId
-                    + " sessionKey " + roomKeyContent.sessionKey) // from " + event);
-
+            Timber.i("## CRYPTO | onRoomKeyEvent(), Adding key : ${roomKeyContent.roomId}|${roomKeyContent.sessionId}")
             if (null == senderKey) {
                 Timber.e("## onRoomKeyEvent() : key event has no sender key (not encrypted?)")
                 return
@@ -285,7 +282,7 @@ internal class MXMegolmDecryption(private val userId: String,
             keysClaimed = event.getKeysClaimed().toMutableMap()
         }
 
-        Timber.e("## CRYPTO | onRoomKeyEvent addInboundGroupSession ${roomKeyContent.sessionId}")
+        Timber.i("## CRYPTO | onRoomKeyEvent addInboundGroupSession ${roomKeyContent.sessionId}")
         val added = olmDevice.addInboundGroupSession(roomKeyContent.sessionId,
                 roomKeyContent.sessionKey,
                 roomKeyContent.roomId,
@@ -349,10 +346,10 @@ internal class MXMegolmDecryption(private val userId: String,
                             if (olmSessionResult?.sessionId == null) {
                                 // no session with this device, probably because there
                                 // were no one-time keys.
+                                Timber.e("no session with this device $deviceId, probably because there were no one-time keys.")
                                 return@mapCatching
                             }
-                            Timber.v("## CRYPTO | shareKeysWithDevice() : sharing keys for session" +
-                                    " ${body.senderKey}|${body.sessionId} with device $userId:$deviceId")
+                            Timber.i("## CRYPTO | shareKeysWithDevice() : sharing session ${body.sessionId} with device $userId:$deviceId")
 
                             val payloadJson = mutableMapOf<String, Any>("type" to EventType.FORWARDED_ROOM_KEY)
                             runCatching { olmDevice.getInboundGroupSession(body.sessionId, body.senderKey, body.roomId) }
@@ -363,6 +360,7 @@ internal class MXMegolmDecryption(private val userId: String,
                                             },
                                             {
                                                 // TODO
+                                                Timber.e(it, "## CRYPTO | shareKeysWithDevice: failed to get session for request $body")
                                             }
 
                                     )
@@ -370,9 +368,13 @@ internal class MXMegolmDecryption(private val userId: String,
                             val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
                             val sendToDeviceMap = MXUsersDevicesMap<Any>()
                             sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
-                            Timber.v("## CRYPTO | shareKeysWithDevice() : sending to $userId:$deviceId")
+                            Timber.i("## CRYPTO | shareKeysWithDevice() : sending ${body.sessionId} to $userId:$deviceId")
                             val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
-                            sendToDeviceTask.execute(sendToDeviceParams)
+                            try {
+                                sendToDeviceTask.execute(sendToDeviceParams)
+                            } catch (failure: Throwable) {
+                                Timber.e(failure, "## CRYPTO | shareKeysWithDevice() : Failed to send ${body.sessionId} to $userId:$deviceId")
+                            }
                         }
                     }
         }
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 e55cf371189c02d9eb04e17f38616c4676b1a3f3..fd431ce735655ce1f79a9277b0aab09bf80e02bb 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
@@ -217,8 +217,10 @@ internal class MXMegolmEncryption(
         Timber.v("## CRYPTO | shareUserDevicesKey() : starts")
 
         val results = ensureOlmSessionsForDevicesAction.handle(devicesByUser)
-        Timber.v("## CRYPTO | shareUserDevicesKey() : ensureOlmSessionsForDevices succeeds after "
-                + (System.currentTimeMillis() - t0) + " ms")
+        Timber.v(
+                """## CRYPTO | shareUserDevicesKey(): ensureOlmSessionsForDevices succeeds after ${System.currentTimeMillis() - t0} ms"""
+                        .trimMargin()
+        )
         val contentMap = MXUsersDevicesMap<Any>()
         var haveTargets = false
         val userIds = results.userIds
@@ -242,7 +244,7 @@ internal class MXMegolmEncryption(
 
                     continue
                 }
-                Timber.v("## CRYPTO | shareUserDevicesKey() : Sharing keys with device $userId:$deviceID")
+                Timber.i("## CRYPTO | shareUserDevicesKey() : Sharing keys with device $userId:$deviceID")
                 contentMap.setObject(userId, deviceID, messageEncrypter.encryptMessage(payload, listOf(sessionResult.deviceInfo)))
                 haveTargets = true
             }
@@ -270,21 +272,22 @@ internal class MXMegolmEncryption(
 
         if (haveTargets) {
             t0 = System.currentTimeMillis()
-            Timber.v("## CRYPTO | shareUserDevicesKey() : has target")
+            Timber.i("## CRYPTO | shareUserDevicesKey() ${session.sessionId} : has target")
             val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, contentMap)
             try {
                 sendToDeviceTask.execute(sendToDeviceParams)
-                Timber.v("## CRYPTO | shareUserDevicesKey() : sendToDevice succeeds after ${System.currentTimeMillis() - t0} ms")
+                Timber.i("## CRYPTO | shareUserDevicesKey() : sendToDevice succeeds after ${System.currentTimeMillis() - t0} ms")
             } catch (failure: Throwable) {
                 // What to do here...
                 Timber.e("## CRYPTO | shareUserDevicesKey() : Failed to share session <${session.sessionId}> with $devicesByUser ")
             }
         } else {
-            Timber.v("## CRYPTO | shareUserDevicesKey() : no need to sharekey")
+            Timber.i("## CRYPTO | shareUserDevicesKey() : no need to sharekey")
         }
     }
 
     private fun notifyKeyWithHeld(targets: List<UserDevice>, sessionId: String, senderKey: String?, code: WithHeldCode) {
+        Timber.i("## CRYPTO | notifyKeyWithHeld() :sending withheld key for $targets session:$sessionId ")
         val withHeldContent = RoomKeyWithHeldContent(
                 roomId = roomId,
                 senderKey = senderKey,
@@ -393,16 +396,16 @@ internal class MXMegolmEncryption(
                                     userId: String,
                                     deviceId: String,
                                     senderKey: String): Boolean {
-        Timber.d("[MXMegolmEncryption] reshareKey: $sessionId to $userId:$deviceId")
+        Timber.i("## Crypto process reshareKey for $sessionId to $userId:$deviceId")
         val deviceInfo = cryptoStore.getUserDevice(userId, deviceId) ?: return false
-                .also { Timber.w("Device not found") }
+                .also { Timber.w("## Crypto reshareKey: Device not found") }
 
         // Get the chain index of the key we previously sent this device
         val chainIndex = outboundSession?.sharedWithHelper?.wasSharedWith(userId, deviceId) ?: return false
                 .also {
                     // Send a room key with held
                     notifyKeyWithHeld(listOf(UserDevice(userId, deviceId)), sessionId, senderKey, WithHeldCode.UNAUTHORISED)
-                    Timber.w("[MXMegolmEncryption] reshareKey : ERROR : Never share megolm with this device")
+                    Timber.w("## Crypto reshareKey: ERROR : Never share megolm with this device")
                 }
 
         val devicesByUser = mapOf(userId to listOf(deviceInfo))
@@ -411,9 +414,11 @@ internal class MXMegolmEncryption(
         olmSessionResult?.sessionId
                 ?: // no session with this device, probably because there were no one-time keys.
                 // ensureOlmSessionsForDevicesAction has already done the logging, so just skip it.
-                return false
+                return false.also {
+                    Timber.w("## Crypto reshareKey: no session with this device, probably because there were no one-time keys")
+                }
 
-        Timber.d("[MXMegolmEncryption] reshareKey: sharing keys for session $senderKey|$sessionId:$chainIndex with device $userId:$deviceId")
+        Timber.i("[MXMegolmEncryption] reshareKey: sharing keys for session $senderKey|$sessionId:$chainIndex with device $userId:$deviceId")
 
         val payloadJson = mutableMapOf<String, Any>("type" to EventType.FORWARDED_ROOM_KEY)
 
@@ -425,6 +430,7 @@ internal class MXMegolmEncryption(
                         },
                         {
                             // TODO
+                            Timber.e(it, "[MXMegolmEncryption] reshareKey: failed to get session $sessionId|$senderKey|$roomId")
                         }
 
                 )
@@ -432,13 +438,14 @@ internal class MXMegolmEncryption(
         val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
         val sendToDeviceMap = MXUsersDevicesMap<Any>()
         sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
-        Timber.v("## CRYPTO | CRYPTO | reshareKey() : sending to $userId:$deviceId")
+        Timber.i("## CRYPTO | reshareKey() : sending session $sessionId to $userId:$deviceId")
         val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
         return try {
             sendToDeviceTask.execute(sendToDeviceParams)
+            Timber.i("## CRYPTO reshareKey() : successfully send <$sessionId> to $userId:$deviceId")
             true
         } catch (failure: Throwable) {
-            Timber.e(failure, "## CRYPTO | CRYPTO | reshareKey() : fail to send <$sessionId> to $userId:$deviceId")
+            Timber.e(failure, "## CRYPTO reshareKey() : fail to send <$sessionId> to $userId:$deviceId")
             false
         }
     }
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 1871dba0e2ed49ea07c37eddd6ebe6c429cd8c8c..bcad448eb6497928fd3b23e732a2444c19d9d7ba 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
@@ -38,7 +38,6 @@ import org.matrix.android.sdk.internal.task.TaskThread
 import org.matrix.android.sdk.internal.task.configureWith
 import org.matrix.android.sdk.internal.util.JsonCanonicalizer
 import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.internal.util.withoutPrefix
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
@@ -444,7 +443,7 @@ internal class DefaultCrossSigningService @Inject constructor(
         } else {
             // Maybe it's signed by a locally trusted device?
             myMasterKey.signatures?.get(userId)?.forEach { (key, value) ->
-                val potentialDeviceId = key.withoutPrefix("ed25519:")
+                val potentialDeviceId = key.removePrefix("ed25519:")
                 val potentialDevice = myDevices?.firstOrNull { it.deviceId == potentialDeviceId } // cryptoStore.getUserDevice(userId, potentialDeviceId)
                 if (potentialDevice != null && potentialDevice.isVerified) {
                     // Check signature validity?
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 f28fe7d642aca9eb90b90a8b93386bc2fb8015fb..665d770e7f69780469d55661c7538162878af49f 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
@@ -241,9 +241,9 @@ internal class UpdateTrustWorker(context: Context,
     private fun computeRoomShield(activeMemberUserIds: List<String>, roomSummaryEntity: RoomSummaryEntity): RoomEncryptionTrustLevel {
         Timber.d("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} -> $activeMemberUserIds")
         // The set of “all users” depends on the type of room:
-        // For regular / topic rooms, all users including yourself, are considered when decorating a room
+        // For regular / topic rooms which have more than 2 members (including yourself) are considered when decorating a room
         // For 1:1 and group DM rooms, all other users (i.e. excluding yourself) are considered when decorating a room
-        val listToCheck = if (roomSummaryEntity.isDirect) {
+        val listToCheck = if (roomSummaryEntity.isDirect || activeMemberUserIds.size <= 2) {
             activeMemberUserIds.filter { it != myUserId }
         } else {
             activeMemberUserIds
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 72274aa70abade16b80dc5248b2f656ecc8475e2..6b83c4f7d1ba801a84881c7a5dae4b12cbe18318 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
@@ -1679,27 +1679,24 @@ internal class RealmCryptoStore @Inject constructor(
             // Only keep one week history
             realm.where<IncomingGossipingRequestEntity>()
                     .lessThan(IncomingGossipingRequestEntityFields.LOCAL_CREATION_TIMESTAMP, prevWeekTs)
-                    .findAll().let {
-                        Timber.i("## Crypto Clean up ${it.size} IncomingGossipingRequestEntity")
-                        it.deleteAllFromRealm()
-                    }
+                    .findAll()
+                    .also { Timber.i("## Crypto Clean up ${it.size} IncomingGossipingRequestEntity") }
+                    .deleteAllFromRealm()
 
             // Clean the cancelled ones?
             realm.where<OutgoingGossipingRequestEntity>()
                     .equalTo(OutgoingGossipingRequestEntityFields.REQUEST_STATE_STR, OutgoingGossipingRequestState.CANCELLED.name)
                     .equalTo(OutgoingGossipingRequestEntityFields.TYPE_STR, GossipRequestType.KEY.name)
-                    .findAll().let {
-                        Timber.i("## Crypto Clean up ${it.size} OutgoingGossipingRequestEntity")
-                        it.deleteAllFromRealm()
-                    }
+                    .findAll()
+                    .also { Timber.i("## Crypto Clean up ${it.size} OutgoingGossipingRequestEntity") }
+                    .deleteAllFromRealm()
 
             // Only keep one week history
             realm.where<GossipingEventEntity>()
                     .lessThan(GossipingEventEntityFields.AGE_LOCAL_TS, prevWeekTs)
-                    .findAll().let {
-                        Timber.i("## Crypto Clean up ${it.size} GossipingEventEntityFields")
-                        it.deleteAllFromRealm()
-                    }
+                    .findAll()
+                    .also { Timber.i("## Crypto Clean up ${it.size} GossipingEventEntityFields") }
+                    .deleteAllFromRealm()
 
             // Can we do something for WithHeldSessionEntity?
         }
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 7f02750359b8f5be4329e86b5879e77fd1bb4300..a92f5c5bf1b09f4d48c7cb31c96209de8c715cc2 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
@@ -537,11 +537,10 @@ internal class DefaultVerificationService @Inject constructor(
                     // If there is a corresponding request, we can auto accept
                     // as we are the one requesting in first place (or we accepted the request)
                     // I need to check if the pending request was related to this device also
-                    val autoAccept = getExistingVerificationRequest(otherUserId)?.any {
+                    val autoAccept = getExistingVerificationRequests(otherUserId).any {
                         it.transactionId == startReq.transactionId
                                 && (it.requestInfo?.fromDevice == this.deviceId || it.readyInfo?.fromDevice == this.deviceId)
                     }
-                            ?: false
                     val tx = DefaultIncomingSASDefaultVerificationTransaction(
 //                            this,
                             setDeviceVerificationAction,
@@ -837,8 +836,8 @@ internal class DefaultVerificationService @Inject constructor(
             // SAS do not care for now?
         }
 
-        // Now transactions are udated, let's also update Requests
-        val existingRequest = getExistingVerificationRequest(senderId)?.find { it.transactionId == doneReq.transactionId }
+        // Now transactions are updated, let's also update Requests
+        val existingRequest = getExistingVerificationRequests(senderId).find { it.transactionId == doneReq.transactionId }
         if (existingRequest == null) {
             Timber.e("## SAS Received Done for unknown request txId:${doneReq.transactionId}")
             return
@@ -892,7 +891,7 @@ internal class DefaultVerificationService @Inject constructor(
     private fun handleReadyReceived(senderId: String,
                                     readyReq: ValidVerificationInfoReady,
                                     transportCreator: (DefaultVerificationTransaction) -> VerificationTransport) {
-        val existingRequest = getExistingVerificationRequest(senderId)?.find { it.transactionId == readyReq.transactionId }
+        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}")
             return
@@ -1041,9 +1040,9 @@ internal class DefaultVerificationService @Inject constructor(
         }
     }
 
-    override fun getExistingVerificationRequest(otherUserId: String): List<PendingVerificationRequest>? {
+    override fun getExistingVerificationRequests(otherUserId: String): List<PendingVerificationRequest> {
         synchronized(lock = pendingRequests) {
-            return pendingRequests[otherUserId]
+            return pendingRequests[otherUserId].orEmpty()
         }
     }
 
@@ -1205,7 +1204,7 @@ internal class DefaultVerificationService @Inject constructor(
         Timber.i("## Requesting verification to user: $otherUserId with device list $otherDevices")
 
         val targetDevices = otherDevices ?: cryptoStore.getUserDevices(otherUserId)
-                ?.values?.map { it.deviceId } ?: emptyList()
+                ?.values?.map { it.deviceId }.orEmpty()
 
         val requestsForUser = pendingRequests.getOrPut(otherUserId) { mutableListOf() }
 
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 cb254eac3c5b82f3247e340a36e0fec98453fe54..22a190c68e1c21f8fd5736f6ff4436cf18bc47c2 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
@@ -28,7 +28,6 @@ import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager
 import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import org.matrix.android.sdk.internal.extensions.toUnsignedInt
-import org.matrix.android.sdk.internal.util.withoutPrefix
 import org.matrix.olm.OlmSAS
 import org.matrix.olm.OlmUtility
 import timber.log.Timber
@@ -250,7 +249,7 @@ internal abstract class SASDefaultVerificationTransaction(
 
         // cannot be empty because it has been validated
         theirMacSafe.mac.keys.forEach {
-            val keyIDNoPrefix = it.withoutPrefix("ed25519:")
+            val keyIDNoPrefix = it.removePrefix("ed25519:")
             val otherDeviceKey = otherUserKnownDevices?.get(keyIDNoPrefix)?.fingerprint()
             if (otherDeviceKey == null) {
                 Timber.w("## SAS Verification: Could not find device $keyIDNoPrefix to verify")
@@ -273,7 +272,7 @@ internal abstract class SASDefaultVerificationTransaction(
         if (otherCrossSigningMasterKeyPublic != null) {
             // Did the user signed his master key
             theirMacSafe.mac.keys.forEach {
-                val keyIDNoPrefix = it.withoutPrefix("ed25519:")
+                val keyIDNoPrefix = it.removePrefix("ed25519:")
                 if (keyIDNoPrefix == otherCrossSigningMasterKeyPublic) {
                     // Check the signature
                     val mac = macUsingAgreedMethod(otherCrossSigningMasterKeyPublic, baseInfo + it)
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 6c430e859110359c87f865ac633a776a77b63c75..0e3a7a2c49b602f1017e3db7beefd9e65e401ec9 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
@@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.database
 import android.content.Context
 import android.util.Base64
 import androidx.core.content.edit
+import io.realm.Realm
 import org.matrix.android.sdk.BuildConfig
 import org.matrix.android.sdk.internal.session.securestorage.SecretStoringUtils
 import io.realm.RealmConfiguration
@@ -46,7 +47,7 @@ internal class RealmKeysUtils @Inject constructor(context: Context,
     private val sharedPreferences = context.getSharedPreferences("im.vector.matrix.android.keys", Context.MODE_PRIVATE)
 
     private fun generateKeyForRealm(): ByteArray {
-        val keyForRealm = ByteArray(RealmConfiguration.KEY_LENGTH)
+        val keyForRealm = ByteArray(Realm.ENCRYPTION_KEY_LENGTH)
         rng.nextBytes(keyForRealm)
         return keyForRealm
     }
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 3324520d294a10b34544e799efb88c10e175290e..244fe3432acf6c26e3c8944e7ad0fbdbca9a0c95 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
@@ -69,6 +69,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
                 .apply {
                     realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5))
                 }
+                .allowWritesOnUiThread(true)
                 .modules(SessionRealmModule())
                 .schemaVersion(RealmSessionStoreMigration.SESSION_STORE_SCHEMA_VERSION)
                 .migration(migration)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/TimeOutInterceptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/TimeOutInterceptor.kt
index 6c604f232f0f1d24dfbbaf9434f56a327cf4710b..724ec0dc7f0dfc560697a7e5e170dd2945a47e8c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/TimeOutInterceptor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/TimeOutInterceptor.kt
@@ -52,5 +52,8 @@ internal class TimeOutInterceptor @Inject constructor() : Interceptor {
         const val CONNECT_TIMEOUT = "CONNECT_TIMEOUT"
         const val READ_TIMEOUT = "READ_TIMEOUT"
         const val WRITE_TIMEOUT = "WRITE_TIMEOUT"
+
+        // 1 minute
+        const val DEFAULT_LONG_TIMEOUT: Long = 60_000
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultRawService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultRawService.kt
index be01366efae2301efe68bc9cf1399cafc191486a..3b0d7546e50f69f7f03ef617806d7453cfa7d11a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultRawService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/DefaultRawService.kt
@@ -16,45 +16,28 @@
 
 package org.matrix.android.sdk.internal.raw
 
-import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.raw.RawCacheStrategy
 import org.matrix.android.sdk.api.raw.RawService
-import org.matrix.android.sdk.api.util.Cancelable
-import org.matrix.android.sdk.internal.task.TaskExecutor
-import org.matrix.android.sdk.internal.task.configureWith
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 
 internal class DefaultRawService @Inject constructor(
-        private val taskExecutor: TaskExecutor,
         private val getUrlTask: GetUrlTask,
         private val cleanRawCacheTask: CleanRawCacheTask
 ) : RawService {
-    override fun getUrl(url: String,
-                        rawCacheStrategy: RawCacheStrategy,
-                        matrixCallback: MatrixCallback<String>): Cancelable {
-        return getUrlTask
-                .configureWith(GetUrlTask.Params(url, rawCacheStrategy)) {
-                    callback = matrixCallback
-                }
-                .executeBy(taskExecutor)
+    override suspend fun getUrl(url: String, rawCacheStrategy: RawCacheStrategy): String {
+        return getUrlTask.execute(GetUrlTask.Params(url, rawCacheStrategy))
     }
 
-    override fun getWellknown(userId: String,
-                              matrixCallback: MatrixCallback<String>): Cancelable {
+    override suspend fun getWellknown(userId: String): String {
         val homeServerDomain = userId.substringAfter(":")
         return getUrl(
                 "https://$homeServerDomain/.well-known/matrix/client",
-                RawCacheStrategy.TtlCache(TimeUnit.HOURS.toMillis(8), false),
-                matrixCallback
+                RawCacheStrategy.TtlCache(TimeUnit.HOURS.toMillis(8), false)
         )
     }
 
-    override fun clearCache(matrixCallback: MatrixCallback<Unit>): Cancelable {
-        return cleanRawCacheTask
-                .configureWith(Unit) {
-                    callback = matrixCallback
-                }
-                .executeBy(taskExecutor)
+    override suspend fun clearCache() {
+        cleanRawCacheTask.execute(Unit)
     }
 }
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 31a39d45e5e562e024f33672bb5fa221e8020aad..1165d2116bb5925ec43b967ab8a36b4df268db8f 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
@@ -16,30 +16,17 @@
 
 package org.matrix.android.sdk.internal.session.account
 
-import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.session.account.AccountService
-import org.matrix.android.sdk.api.util.Cancelable
-import org.matrix.android.sdk.internal.task.TaskExecutor
-import org.matrix.android.sdk.internal.task.configureWith
 import javax.inject.Inject
 
 internal class DefaultAccountService @Inject constructor(private val changePasswordTask: ChangePasswordTask,
-                                                         private val deactivateAccountTask: DeactivateAccountTask,
-                                                         private val taskExecutor: TaskExecutor) : AccountService {
+                                                         private val deactivateAccountTask: DeactivateAccountTask) : AccountService {
 
-    override fun changePassword(password: String, newPassword: String, callback: MatrixCallback<Unit>): Cancelable {
-        return changePasswordTask
-                .configureWith(ChangePasswordTask.Params(password, newPassword)) {
-                    this.callback = callback
-                }
-                .executeBy(taskExecutor)
+    override suspend fun changePassword(password: String, newPassword: String) {
+        changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword))
     }
 
-    override fun deactivateAccount(password: String, eraseAllData: Boolean, callback: MatrixCallback<Unit>): Cancelable {
-        return deactivateAccountTask
-                .configureWith(DeactivateAccountTask.Params(password, eraseAllData)) {
-                    this.callback = callback
-                }
-                .executeBy(taskExecutor)
+    override suspend fun deactivateAccount(password: String, eraseAllData: Boolean) {
+        deactivateAccountTask.execute(DeactivateAccountTask.Params(password, eraseAllData))
     }
 }
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 01b57767b38845964e45c8802edba02c2dca4f91..4f610fd81bfe4176c6febcd8a89bfb80cc499e41 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
@@ -16,20 +16,13 @@
 
 package org.matrix.android.sdk.internal.session.group
 
-import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.session.group.Group
-import org.matrix.android.sdk.api.util.Cancelable
-import org.matrix.android.sdk.internal.task.TaskExecutor
-import org.matrix.android.sdk.internal.task.configureWith
 
 internal class DefaultGroup(override val groupId: String,
-                            private val taskExecutor: TaskExecutor,
                             private val getGroupDataTask: GetGroupDataTask) : Group {
 
-    override fun fetchGroupData(callback: MatrixCallback<Unit>): Cancelable {
+    override suspend fun fetchGroupData() {
         val params = GetGroupDataTask.Params.FetchWithIds(listOf(groupId))
-        return getGroupDataTask.configureWith(params) {
-            this.callback = callback
-        }.executeBy(taskExecutor)
+        getGroupDataTask.execute(params)
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GroupFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GroupFactory.kt
index 31450763d85e6bba922d5533d64f974e7c944645..653d2a69331615b24ba985dfaa85ca6ffb11d6ce 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GroupFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GroupFactory.kt
@@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.session.group
 
 import org.matrix.android.sdk.api.session.group.Group
 import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.task.TaskExecutor
 import javax.inject.Inject
 
 internal interface GroupFactory {
@@ -26,14 +25,12 @@ internal interface GroupFactory {
 }
 
 @SessionScope
-internal class DefaultGroupFactory @Inject constructor(private val getGroupDataTask: GetGroupDataTask,
-                                                       private val taskExecutor: TaskExecutor) :
+internal class DefaultGroupFactory @Inject constructor(private val getGroupDataTask: GetGroupDataTask) :
         GroupFactory {
 
     override fun create(groupId: String): Group {
         return DefaultGroup(
                 groupId = groupId,
-                taskExecutor = taskExecutor,
                 getGroupDataTask = getGroupDataTask
         )
     }
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 20f8b7f868f71c52f8d18f5a1fa2692a1dee1dbc..c6fb34151c8dbba34843129168fae7ea63b996b7 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
@@ -55,6 +55,7 @@ import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
 import org.matrix.android.sdk.internal.util.ensureProtocol
 import kotlinx.coroutines.withContext
 import okhttp3.OkHttpClient
+import org.matrix.android.sdk.api.extensions.orFalse
 import timber.log.Timber
 import javax.inject.Inject
 import javax.net.ssl.HttpsURLConnection
@@ -243,7 +244,20 @@ internal class DefaultIdentityService @Inject constructor(
         ))
     }
 
+    override fun getUserConsent(): Boolean {
+        return identityStore.getIdentityData()?.userConsent.orFalse()
+    }
+
+    override fun setUserConsent(newValue: Boolean) {
+        identityStore.setUserConsent(newValue)
+    }
+
     override fun lookUp(threePids: List<ThreePid>, callback: MatrixCallback<List<FoundThreePid>>): Cancelable {
+        if (!getUserConsent()) {
+            callback.onFailure(IdentityServiceError.UserConsentNotProvided)
+            return NoOpCancellable
+        }
+
         if (threePids.isEmpty()) {
             callback.onSuccess(emptyList())
             return NoOpCancellable
@@ -255,6 +269,9 @@ internal class DefaultIdentityService @Inject constructor(
     }
 
     override fun getShareStatus(threePids: List<ThreePid>, callback: MatrixCallback<Map<ThreePid, SharedState>>): Cancelable {
+        // Note: we do not require user consent here, because it is used for emails and phone numbers that the user has already sent
+        // to the home server, and not emails and phone numbers from the contact book of the user
+
         if (threePids.isEmpty()) {
             callback.onSuccess(emptyMap())
             return NoOpCancellable
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 1bb57b47cd1e7b4d6c9328011bbe74ed4e213d29..7a39a333a59bd7b039ddf51915c807d5993f12e8 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
@@ -34,6 +34,7 @@ import org.matrix.android.sdk.internal.session.identity.db.IdentityRealmModule
 import org.matrix.android.sdk.internal.session.identity.db.RealmIdentityStore
 import io.realm.RealmConfiguration
 import okhttp3.OkHttpClient
+import org.matrix.android.sdk.internal.session.identity.db.RealmIdentityStoreMigration
 import java.io.File
 
 @Module
@@ -59,6 +60,7 @@ internal abstract class IdentityModule {
         @SessionScope
         fun providesIdentityRealmConfiguration(realmKeysUtils: RealmKeysUtils,
                                                @SessionFilesDirectory directory: File,
+                                               migration: RealmIdentityStoreMigration,
                                                @UserMd5 userMd5: String): RealmConfiguration {
             return RealmConfiguration.Builder()
                     .directory(directory)
@@ -66,6 +68,9 @@ internal abstract class IdentityModule {
                     .apply {
                         realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5))
                     }
+                    .schemaVersion(RealmIdentityStoreMigration.IDENTITY_STORE_SCHEMA_VERSION)
+                    .migration(migration)
+                    .allowWritesOnUiThread(true)
                     .modules(IdentityRealmModule())
                     .build()
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityData.kt
index 0f04f2fe1a2bf20e939ab691a88cb5a7bdda5174..54d35b34fa7bf3c361dce59ffd843edf4e15b42f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityData.kt
@@ -20,5 +20,6 @@ internal data class IdentityData(
         val identityServerUrl: String?,
         val token: String?,
         val hashLookupPepper: String?,
-        val hashLookupAlgorithm: List<String>
+        val hashLookupAlgorithm: List<String>,
+        val userConsent: Boolean
 )
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityStore.kt
index 3a905833d5182ac596e306c0fe0fba3b070df080..0e05224be5db88716aa025f39eb99a2345c08679 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityStore.kt
@@ -27,6 +27,8 @@ internal interface IdentityStore {
 
     fun setToken(token: String?)
 
+    fun setUserConsent(consent: Boolean)
+
     fun setHashDetails(hashDetailResponse: IdentityHashDetailResponse)
 
     /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntity.kt
index cc03465cc808edb2f63e72f0bab93b774efdab8d..019289a8842cc5f1c12525bb51da67f852fe23ca 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntity.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntity.kt
@@ -23,7 +23,8 @@ internal open class IdentityDataEntity(
         var identityServerUrl: String? = null,
         var token: String? = null,
         var hashLookupPepper: String? = null,
-        var hashLookupAlgorithm: RealmList<String> = RealmList()
+        var hashLookupAlgorithm: RealmList<String> = RealmList(),
+        var userConsent: Boolean = false
 ) : RealmObject() {
 
     companion object
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 062c28ea55f3b5929946120bd734e194a852aef9..5152e33743640057512747a5796be732a65467e5 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
@@ -52,6 +52,13 @@ internal fun IdentityDataEntity.Companion.setToken(realm: Realm,
     }
 }
 
+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>) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityMapper.kt
index 98207f1b388ba1df3a5841bf528ac152c72f7b88..bf23c058115c2cb40408a5c0410b119f6a9b433c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityMapper.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityMapper.kt
@@ -26,7 +26,8 @@ internal object IdentityMapper {
                 identityServerUrl = entity.identityServerUrl,
                 token = entity.token,
                 hashLookupPepper = entity.hashLookupPepper,
-                hashLookupAlgorithm = entity.hashLookupAlgorithm.toList()
+                hashLookupAlgorithm = entity.hashLookupAlgorithm.toList(),
+                userConsent = entity.userConsent
         )
     }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStore.kt
index 0352e9b9369d70d76c7b8bd551a796ddf8e7b9e6..2fa3fc0cfb2598a0418c19a2a3efd67f72bf9515 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStore.kt
@@ -55,6 +55,14 @@ internal class RealmIdentityStore @Inject constructor(
         }
     }
 
+    override fun setUserConsent(consent: Boolean) {
+        Realm.getInstance(realmConfiguration).use {
+            it.executeTransaction { realm ->
+                IdentityDataEntity.setUserConsent(realm, consent)
+            }
+        }
+    }
+
     override fun setHashDetails(hashDetailResponse: IdentityHashDetailResponse) {
         Realm.getInstance(realmConfiguration).use {
             it.executeTransaction { realm ->
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6081dbab12e5a59fa77e667dec09f35c2cca1770
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.session.identity.db
+
+import io.realm.DynamicRealm
+import io.realm.RealmMigration
+import timber.log.Timber
+import javax.inject.Inject
+
+internal class RealmIdentityStoreMigration @Inject constructor() : RealmMigration {
+
+    companion object {
+        const val IDENTITY_STORE_SCHEMA_VERSION = 1L
+    }
+
+    override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
+        Timber.v("Migrating Realm Identity from $oldVersion to $newVersion")
+
+        if (oldVersion <= 0) migrateTo1(realm)
+    }
+
+    private fun migrateTo1(realm: DynamicRealm) {
+        Timber.d("Step 0 -> 1")
+        Timber.d("Add field userConsent (Boolean) and set the value to false")
+
+        realm.schema.get("IdentityDataEntity")
+                ?.addField(IdentityDataEntityFields.USER_CONSENT, Boolean::class.java)
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/DefaultPushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/DefaultPushRuleService.kt
index 217da269f9dee9b9e1d9ac748ca14b2dc157f8ba..e00d2ff26cf1fbdfc01f423314052dc7c1735807 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/DefaultPushRuleService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/DefaultPushRuleService.kt
@@ -16,7 +16,6 @@
 package org.matrix.android.sdk.internal.session.notification
 
 import com.zhuinden.monarchy.Monarchy
-import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.pushrules.PushRuleService
 import org.matrix.android.sdk.api.pushrules.RuleKind
 import org.matrix.android.sdk.api.pushrules.RuleSetKey
@@ -24,7 +23,6 @@ import org.matrix.android.sdk.api.pushrules.getActions
 import org.matrix.android.sdk.api.pushrules.rest.PushRule
 import org.matrix.android.sdk.api.pushrules.rest.RuleSet
 import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.util.Cancelable
 import org.matrix.android.sdk.internal.database.mapper.PushRulesMapper
 import org.matrix.android.sdk.internal.database.model.PushRulesEntity
 import org.matrix.android.sdk.internal.database.query.where
@@ -103,37 +101,21 @@ internal class DefaultPushRuleService @Inject constructor(
         )
     }
 
-    override fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback<Unit>): Cancelable {
+    override suspend fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean) {
         // The rules will be updated, and will come back from the next sync response
-        return updatePushRuleEnableStatusTask
-                .configureWith(UpdatePushRuleEnableStatusTask.Params(kind, pushRule, enabled)) {
-                    this.callback = callback
-                }
-                .executeBy(taskExecutor)
+        updatePushRuleEnableStatusTask.execute(UpdatePushRuleEnableStatusTask.Params(kind, pushRule, enabled))
     }
 
-    override fun addPushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable {
-        return addPushRuleTask
-                .configureWith(AddPushRuleTask.Params(kind, pushRule)) {
-                    this.callback = callback
-                }
-                .executeBy(taskExecutor)
+    override suspend fun addPushRule(kind: RuleKind, pushRule: PushRule) {
+        addPushRuleTask.execute(AddPushRuleTask.Params(kind, pushRule))
     }
 
-    override fun updatePushRuleActions(kind: RuleKind, oldPushRule: PushRule, newPushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable {
-        return updatePushRuleActionsTask
-                .configureWith(UpdatePushRuleActionsTask.Params(kind, oldPushRule, newPushRule)) {
-                    this.callback = callback
-                }
-                .executeBy(taskExecutor)
+    override suspend fun updatePushRuleActions(kind: RuleKind, oldPushRule: PushRule, newPushRule: PushRule) {
+        updatePushRuleActionsTask.execute(UpdatePushRuleActionsTask.Params(kind, oldPushRule, newPushRule))
     }
 
-    override fun removePushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback<Unit>): Cancelable {
-        return removePushRuleTask
-                .configureWith(RemovePushRuleTask.Params(kind, pushRule)) {
-                    this.callback = callback
-                }
-                .executeBy(taskExecutor)
+    override suspend fun removePushRule(kind: RuleKind, pushRule: PushRule) {
+        removePushRuleTask.execute(RemovePushRuleTask.Params(kind, pushRule))
     }
 
     override fun removePushRuleListener(listener: PushRuleService.PushRuleListener) {
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 8d092772954c460d84d40d82d9469dd452730b49..5265e4f17daef589417f480940c3baad4c21fffc 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
@@ -31,6 +31,7 @@ import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity
 import org.matrix.android.sdk.internal.database.model.UserThreePidEntity
 import org.matrix.android.sdk.internal.di.SessionDatabase
 import org.matrix.android.sdk.internal.session.content.FileUploader
+import org.matrix.android.sdk.internal.session.user.UserStore
 import org.matrix.android.sdk.internal.task.TaskExecutor
 import org.matrix.android.sdk.internal.task.configureWith
 import org.matrix.android.sdk.internal.task.launchToCallback
@@ -49,6 +50,7 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
                                                          private val finalizeAddingThreePidTask: FinalizeAddingThreePidTask,
                                                          private val deleteThreePidTask: DeleteThreePidTask,
                                                          private val pendingThreePidMapper: PendingThreePidMapper,
+                                                         private val userStore: UserStore,
                                                          private val fileUploader: FileUploader) : ProfileService {
 
     override fun getDisplayName(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable {
@@ -70,17 +72,17 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
     }
 
     override fun setDisplayName(userId: String, newDisplayName: String, matrixCallback: MatrixCallback<Unit>): Cancelable {
-        return setDisplayNameTask
-                .configureWith(SetDisplayNameTask.Params(userId = userId, newDisplayName = newDisplayName)) {
-                    callback = matrixCallback
-                }
-                .executeBy(taskExecutor)
+        return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.io, matrixCallback) {
+            setDisplayNameTask.execute(SetDisplayNameTask.Params(userId = userId, newDisplayName = newDisplayName))
+            userStore.updateDisplayName(userId, newDisplayName)
+        }
     }
 
     override fun updateAvatar(userId: String, newAvatarUri: Uri, fileName: String, matrixCallback: MatrixCallback<Unit>): Cancelable {
         return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, matrixCallback) {
             val response = fileUploader.uploadFromUri(newAvatarUri, fileName, "image/jpeg")
             setAvatarUrlTask.execute(SetAvatarUrlTask.Params(userId = userId, newAvatarUrl = response.contentUri))
+            userStore.updateAvatar(userId, response.contentUri)
         }
     }
 
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 1338df6878803ebae511c3376d607829d4bc22f1..c7bb640f7cebec6a3595492bc369f8dc62ab60ab 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
@@ -101,13 +101,13 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
         return cryptoService.shouldEncryptForInvitedMembers(roomId)
     }
 
-    override fun enableEncryption(algorithm: String, callback: MatrixCallback<Unit>) {
+    override suspend fun enableEncryption(algorithm: String) {
         when {
             isEncrypted()                          -> {
-                callback.onFailure(IllegalStateException("Encryption is already enabled for this room"))
+                throw IllegalStateException("Encryption is already enabled for this room")
             }
             algorithm != MXCRYPTO_ALGORITHM_MEGOLM -> {
-                callback.onFailure(InvalidParameterException("Only MXCRYPTO_ALGORITHM_MEGOLM algorithm is supported"))
+                throw InvalidParameterException("Only MXCRYPTO_ALGORITHM_MEGOLM algorithm is supported")
             }
             else                                   -> {
                 val params = SendStateTask.Params(
@@ -118,11 +118,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
                                 "algorithm" to algorithm
                         ))
 
-                sendStateTask
-                        .configureWith(params) {
-                            this.callback = callback
-                        }
-                        .executeBy(taskExecutor)
+                sendStateTask.execute(params)
             }
         }
     }
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 d49c2f120cc5026b6c9b78d8863f917e08ab9a64..28656463c10fce184a1229b265d5f3b075c10dfc 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
@@ -17,27 +17,37 @@
 package org.matrix.android.sdk.internal.session.room
 
 import androidx.lifecycle.LiveData
+import androidx.lifecycle.Transformations
+import com.zhuinden.monarchy.Monarchy
 import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.session.room.Room
 import org.matrix.android.sdk.api.session.room.RoomService
 import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
 import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
+import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
 import org.matrix.android.sdk.api.session.room.model.RoomSummary
 import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
 import org.matrix.android.sdk.api.util.Cancelable
 import org.matrix.android.sdk.api.util.Optional
+import org.matrix.android.sdk.api.util.toOptional
+import org.matrix.android.sdk.internal.database.mapper.asDomain
+import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
+import org.matrix.android.sdk.internal.di.SessionDatabase
 import org.matrix.android.sdk.internal.session.room.alias.GetRoomIdByAliasTask
 import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask
 import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembershipStateDataSource
+import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
 import org.matrix.android.sdk.internal.session.room.membership.joining.JoinRoomTask
 import org.matrix.android.sdk.internal.session.room.read.MarkAllRoomsReadTask
 import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource
 import org.matrix.android.sdk.internal.session.user.accountdata.UpdateBreadcrumbsTask
 import org.matrix.android.sdk.internal.task.TaskExecutor
 import org.matrix.android.sdk.internal.task.configureWith
+import org.matrix.android.sdk.internal.util.fetchCopied
 import javax.inject.Inject
 
 internal class DefaultRoomService @Inject constructor(
+        @SessionDatabase private val monarchy: Monarchy,
         private val createRoomTask: CreateRoomTask,
         private val joinRoomTask: JoinRoomTask,
         private val markAllRoomsReadTask: MarkAllRoomsReadTask,
@@ -118,4 +128,24 @@ internal class DefaultRoomService @Inject constructor(
     override fun getChangeMembershipsLive(): LiveData<Map<String, ChangeMembershipState>> {
         return roomChangeMembershipStateDataSource.getLiveStates()
     }
+
+    override fun getRoomMember(userId: String, roomId: String): RoomMemberSummary? {
+        val roomMemberEntity = monarchy.fetchCopied {
+            RoomMemberHelper(it, roomId).getLastRoomMember(userId)
+        }
+        return roomMemberEntity?.asDomain()
+    }
+
+    override fun getRoomMemberLive(userId: String, roomId: String): LiveData<Optional<RoomMemberSummary>> {
+        val liveData = monarchy.findAllMappedWithChanges(
+                { realm ->
+                    RoomMemberHelper(realm, roomId).queryRoomMembersEvent()
+                            .equalTo(RoomMemberSummaryEntityFields.USER_ID, userId)
+                },
+                { it.asDomain() }
+        )
+        return Transformations.map(liveData) { results ->
+            results.firstOrNull().toOptional()
+        }
+    }
 }
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 90ee99a91900ec65a38cb5578b1f5ed37083c57d..99f9d3644d58e867a97bb47d3e55df2a622838e9 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
@@ -26,6 +26,8 @@ import org.matrix.android.sdk.internal.database.query.getOrNull
 import org.matrix.android.sdk.internal.di.UserId
 import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
 import io.realm.Realm
+import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
+import org.matrix.android.sdk.internal.database.query.where
 import javax.inject.Inject
 
 internal class RoomAvatarResolver @Inject constructor(@UserId private val userId: String) {
@@ -46,11 +48,14 @@ internal class RoomAvatarResolver @Inject constructor(@UserId private val userId
         val roomMembers = RoomMemberHelper(realm, roomId)
         val members = roomMembers.queryActiveRoomMembersEvent().findAll()
         // detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat)
-        if (members.size == 1) {
-            res = members.firstOrNull()?.avatarUrl
-        } else if (members.size == 2) {
-            val firstOtherMember = members.where().notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId).findFirst()
-            res = firstOtherMember?.avatarUrl
+        val isDirectRoom =  RoomSummaryEntity.where(realm, roomId).findFirst()?.isDirect ?: false
+        if (isDirectRoom) {
+            if (members.size == 1) {
+                res = members.firstOrNull()?.avatarUrl
+            } else if (members.size == 2) {
+                val firstOtherMember = members.where().notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId).findFirst()
+                res = firstOtherMember?.avatarUrl
+            }
         }
         return res
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomIdByAliasTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomIdByAliasTask.kt
index 8b011980d0193865288d84f062caa725d58a2620..58a119cc77b04e73bb76752306faf609bbf3666c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomIdByAliasTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/GetRoomIdByAliasTask.kt
@@ -17,6 +17,9 @@
 package org.matrix.android.sdk.internal.session.room.alias
 
 import com.zhuinden.monarchy.Monarchy
+import io.realm.Realm
+import org.greenrobot.eventbus.EventBus
+import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.util.Optional
 import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
 import org.matrix.android.sdk.internal.database.query.findByAlias
@@ -24,8 +27,6 @@ import org.matrix.android.sdk.internal.di.SessionDatabase
 import org.matrix.android.sdk.internal.network.executeRequest
 import org.matrix.android.sdk.internal.session.room.RoomAPI
 import org.matrix.android.sdk.internal.task.Task
-import io.realm.Realm
-import org.greenrobot.eventbus.EventBus
 import javax.inject.Inject
 
 internal interface GetRoomIdByAliasTask : Task<GetRoomIdByAliasTask.Params, Optional<String>> {
@@ -50,9 +51,11 @@ internal class DefaultGetRoomIdByAliasTask @Inject constructor(
         } else if (!params.searchOnServer) {
             Optional.from<String>(null)
         } else {
-            roomId = executeRequest<RoomAliasDescription>(eventBus) {
-                apiCall = roomAPI.getRoomIdByAlias(params.roomAlias)
-            }.roomId
+            roomId = tryOrNull("## Failed to get roomId from alias") {
+                executeRequest<RoomAliasDescription>(eventBus) {
+                    apiCall = roomAPI.getRoomIdByAlias(params.roomAlias)
+                }
+            }?.roomId
             Optional.from(roomId)
         }
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt
index c30f11b9affb8f404687cf69d4d22559c75c9adb..13d403e2e4bee4588988a6ebc70790d78d4e81aa 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBody.kt
@@ -74,8 +74,8 @@ internal data class CreateRoomBody(
         val invite3pids: List<ThreePidInviteBody>?,
 
         /**
-         * Extra keys to be added to the content of the m.room.create.
-         * The server will clobber the following keys: creator.
+         * Extra keys, such as m.federate, to be added to the content of the m.room.create event.
+         * The server will clobber the following keys: creator, room_version.
          * Future versions of the specification may allow the server to clobber other keys.
          */
         @Json(name = "creation_content")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
index 632fcab70b77009b41252cc8f95cad5ee1bd46de..79ff9db087163fc51aa81283c0530533fc3e3c70 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
@@ -81,7 +81,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
                 topic = params.topic,
                 invitedUserIds = params.invitedUserIds,
                 invite3pids = invite3pids,
-                creationContent = params.creationContent,
+                creationContent = params.creationContent.takeIf { it.isNotEmpty() },
                 initialStates = initialStates,
                 preset = params.preset,
                 isDirect = params.isDirect,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt
index 4f0aaf083d52e1bd342f8723772f4671061ce253..0fe9b0ba682bd877eaad9d53d50f9e293a603f6f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomTask.kt
@@ -31,8 +31,10 @@ import org.matrix.android.sdk.internal.database.model.RoomEntityFields
 import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
 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
 import org.matrix.android.sdk.internal.network.executeRequest
 import org.matrix.android.sdk.internal.session.room.RoomAPI
+import org.matrix.android.sdk.internal.session.room.alias.RoomAliasDescription
 import org.matrix.android.sdk.internal.session.room.read.SetReadMarkersTask
 import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper
 import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
@@ -45,6 +47,7 @@ internal interface CreateRoomTask : Task<CreateRoomParams, String>
 
 internal class DefaultCreateRoomTask @Inject constructor(
         private val roomAPI: RoomAPI,
+        @UserId private val userId: String,
         @SessionDatabase private val monarchy: Monarchy,
         private val directChatsHelper: DirectChatsHelper,
         private val updateUserAccountDataTask: UpdateUserAccountDataTask,
@@ -61,6 +64,31 @@ internal class DefaultCreateRoomTask @Inject constructor(
                     ?: throw IllegalStateException("You can't create a direct room without an invitedUser")
         } else null
 
+        if (params.preset == CreateRoomPreset.PRESET_PUBLIC_CHAT) {
+            if (params.roomAliasName.isNullOrEmpty()) {
+                throw CreateRoomFailure.RoomAliasError.AliasEmpty
+            }
+            // Check alias availability
+            val fullAlias = "#" + params.roomAliasName + ":" + userId.substringAfter(":")
+            try {
+                executeRequest<RoomAliasDescription>(eventBus) {
+                    apiCall = roomAPI.getRoomIdByAlias(fullAlias)
+                }
+            } catch (throwable: Throwable) {
+                if (throwable is Failure.ServerError && throwable.httpCode == 404) {
+                    // This is a 404, so the alias is available: nominal case
+                    null
+                } else {
+                    // Other error, propagate it
+                    throw throwable
+                }
+            }
+                    ?.let {
+                        // Alias already exists: error case
+                        throw CreateRoomFailure.RoomAliasError.AliasNotAvailable
+                    }
+        }
+
         val createRoomBody = createRoomBodyBuilder.build(params)
 
         val createRoomResponse = try {
@@ -68,14 +96,18 @@ internal class DefaultCreateRoomTask @Inject constructor(
                 apiCall = roomAPI.createRoom(createRoomBody)
             }
         } catch (throwable: Throwable) {
-            if (throwable is Failure.ServerError
-                    && throwable.httpCode == 403
-                    && throwable.error.code == MatrixError.M_FORBIDDEN
-                    && throwable.error.message.startsWith("Federation denied with")) {
-                throw CreateRoomFailure.CreatedWithFederationFailure(throwable.error)
-            } else {
-                throw throwable
+            if (throwable is Failure.ServerError) {
+                if (throwable.httpCode == 403
+                        && throwable.error.code == MatrixError.M_FORBIDDEN
+                        && throwable.error.message.startsWith("Federation denied with")) {
+                    throw CreateRoomFailure.CreatedWithFederationFailure(throwable.error)
+                } else if (throwable.httpCode == 400
+                        && throwable.error.code == MatrixError.M_UNKNOWN
+                        && throwable.error.message == "Invalid characters in room alias") {
+                    throw CreateRoomFailure.RoomAliasError.AliasInvalid
+                }
             }
+            throw throwable
         }
         val roomId = createRoomResponse.roomId
         // Wait for room to come back from the sync (but it can maybe be in the DB if the sync response is received before)
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 92e16a3501930ba61b005ac3b0fc1b6752a1cc50..93fbfb4df0c4fc967d8ba1a46dae51f7271ea295 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
@@ -19,18 +19,14 @@ package org.matrix.android.sdk.internal.session.room.draft
 import androidx.lifecycle.LiveData
 import com.squareup.inject.assisted.Assisted
 import com.squareup.inject.assisted.AssistedInject
-import org.matrix.android.sdk.api.MatrixCallback
+import kotlinx.coroutines.withContext
 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.Cancelable
 import org.matrix.android.sdk.api.util.Optional
-import org.matrix.android.sdk.internal.task.TaskExecutor
-import org.matrix.android.sdk.internal.task.launchToCallback
 import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
 
 internal class DefaultDraftService @AssistedInject constructor(@Assisted private val roomId: String,
                                                                private val draftRepository: DraftRepository,
-                                                               private val taskExecutor: TaskExecutor,
                                                                private val coroutineDispatchers: MatrixCoroutineDispatchers
 ) : DraftService {
 
@@ -43,14 +39,14 @@ internal class DefaultDraftService @AssistedInject constructor(@Assisted private
      * The draft stack can contain several drafts. Depending of the draft to save, it will update the top draft, or create a new draft,
      * or even move an existing draft to the top of the list
      */
-    override fun saveDraft(draft: UserDraft, callback: MatrixCallback<Unit>): Cancelable {
-        return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, callback) {
+    override suspend fun saveDraft(draft: UserDraft) {
+        withContext(coroutineDispatchers.main) {
             draftRepository.saveDraft(roomId, draft)
         }
     }
 
-    override fun deleteDraft(callback: MatrixCallback<Unit>): Cancelable {
-        return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, callback) {
+    override suspend fun deleteDraft() {
+        withContext(coroutineDispatchers.main) {
             draftRepository.deleteDraft(roomId)
         }
     }
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 7f3796c1ce796a14eacdac6ad3f822a320f725f5..a7dfcfc96f5e1b1bdaeaa4e442f3db2b5b58ebef 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
@@ -93,6 +93,8 @@ internal class RoomDisplayNameResolver @Inject constructor(
             }
         } else if (roomEntity?.membership == Membership.JOIN) {
             val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst()
+            val invitedCount = roomSummary?.invitedMembersCount ?: 0
+            val joinedCount = roomSummary?.joinedMembersCount ?: 0
             val otherMembersSubset: List<RoomMemberSummaryEntity> = if (roomSummary?.heroes?.isNotEmpty() == true) {
                 roomSummary.heroes.mapNotNull { userId ->
                     roomMembers.getLastRoomMember(userId)?.takeIf {
@@ -102,22 +104,49 @@ internal class RoomDisplayNameResolver @Inject constructor(
             } else {
                 activeMembers.where()
                         .notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId)
-                        .limit(3)
+                        .limit(5)
                         .findAll()
                         .createSnapshot()
             }
             val otherMembersCount = otherMembersSubset.count()
             name = when (otherMembersCount) {
-                0    -> stringProvider.getString(R.string.room_displayname_empty_room)
+                0    -> {
+                    stringProvider.getString(R.string.room_displayname_empty_room)
+                    // TODO (was xx and yyy) ...
+                }
                 1    -> resolveRoomMemberName(otherMembersSubset[0], roomMembers)
-                2    -> stringProvider.getString(R.string.room_displayname_two_members,
-                        resolveRoomMemberName(otherMembersSubset[0], roomMembers),
-                        resolveRoomMemberName(otherMembersSubset[1], roomMembers)
-                )
-                else -> stringProvider.getQuantityString(R.plurals.room_displayname_three_and_more_members,
-                        roomMembers.getNumberOfJoinedMembers() - 1,
-                        resolveRoomMemberName(otherMembersSubset[0], roomMembers),
-                        roomMembers.getNumberOfJoinedMembers() - 1)
+                2    -> {
+                    stringProvider.getString(R.string.room_displayname_two_members,
+                            resolveRoomMemberName(otherMembersSubset[0], roomMembers),
+                            resolveRoomMemberName(otherMembersSubset[1], roomMembers)
+                    )
+                }
+                3    -> {
+                    stringProvider.getString(R.string.room_displayname_3_members,
+                            resolveRoomMemberName(otherMembersSubset[0], roomMembers),
+                            resolveRoomMemberName(otherMembersSubset[1], roomMembers),
+                            resolveRoomMemberName(otherMembersSubset[2], roomMembers)
+                    )
+                }
+                4    -> {
+                    stringProvider.getString(R.string.room_displayname_4_members,
+                            resolveRoomMemberName(otherMembersSubset[0], roomMembers),
+                            resolveRoomMemberName(otherMembersSubset[1], roomMembers),
+                            resolveRoomMemberName(otherMembersSubset[2], roomMembers),
+                            resolveRoomMemberName(otherMembersSubset[3], roomMembers)
+                    )
+                }
+                else -> {
+                    val remainingCount = invitedCount + joinedCount - otherMembersCount + 1
+                    stringProvider.getQuantityString(
+                            R.plurals.room_displayname_four_and_more_members,
+                            remainingCount,
+                            resolveRoomMemberName(otherMembersSubset[0], roomMembers),
+                            resolveRoomMemberName(otherMembersSubset[1], roomMembers),
+                            resolveRoomMemberName(otherMembersSubset[2], roomMembers),
+                            remainingCount
+                    )
+                }
             }
         }
         return name ?: roomId
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 7105a2cc225734c056ff2a8f6c19a54ab191cbf2..2a7c46bd4238fff80d69c97f6f9b56bcbdda7218 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
@@ -16,6 +16,8 @@
 
 package org.matrix.android.sdk.internal.session.room.membership
 
+import io.realm.Realm
+import io.realm.RealmQuery
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
@@ -25,8 +27,6 @@ import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFie
 import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
 import org.matrix.android.sdk.internal.database.query.getOrNull
 import org.matrix.android.sdk.internal.database.query.where
-import io.realm.Realm
-import io.realm.RealmQuery
 
 /**
  * This class is an helper around STATE_ROOM_MEMBER events.
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 8797b0c764b19502f2114463196144796d88d2d5..67ae55c066e28b59d4fff26d8691928f20a0b94f 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
@@ -21,21 +21,16 @@ import androidx.lifecycle.Transformations
 import com.squareup.inject.assisted.Assisted
 import com.squareup.inject.assisted.AssistedInject
 import com.zhuinden.monarchy.Monarchy
-import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.pushrules.RuleScope
 import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
 import org.matrix.android.sdk.api.session.room.notification.RoomPushRuleService
-import org.matrix.android.sdk.api.util.Cancelable
 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
-import org.matrix.android.sdk.internal.task.TaskExecutor
-import org.matrix.android.sdk.internal.task.configureWith
 
 internal class DefaultRoomPushRuleService @AssistedInject constructor(@Assisted private val roomId: String,
                                                                       private val setRoomNotificationStateTask: SetRoomNotificationStateTask,
-                                                                      @SessionDatabase private val monarchy: Monarchy,
-                                                                      private val taskExecutor: TaskExecutor)
+                                                                      @SessionDatabase private val monarchy: Monarchy)
     : RoomPushRuleService {
 
     @AssistedInject.Factory
@@ -49,12 +44,8 @@ internal class DefaultRoomPushRuleService @AssistedInject constructor(@Assisted
         }
     }
 
-    override fun setRoomNotificationState(roomNotificationState: RoomNotificationState, matrixCallback: MatrixCallback<Unit>): Cancelable {
-        return setRoomNotificationStateTask
-                .configureWith(SetRoomNotificationStateTask.Params(roomId, roomNotificationState)) {
-                    this.callback = matrixCallback
-                }
-                .executeBy(taskExecutor)
+    override suspend fun setRoomNotificationState(roomNotificationState: RoomNotificationState) {
+        setRoomNotificationStateTask.execute(SetRoomNotificationStateTask.Params(roomId, roomNotificationState))
     }
 
     private fun getPushRuleForRoom(): LiveData<RoomPushRule?> {
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 384c544ee0064e0e2d52ac54ff1f771af95adf7d..cac87a9d30cf3ff2b6b5727582192ff5b45a0ad3 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
@@ -18,14 +18,9 @@ package org.matrix.android.sdk.internal.session.room.reporting
 
 import com.squareup.inject.assisted.Assisted
 import com.squareup.inject.assisted.AssistedInject
-import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.session.room.reporting.ReportingService
-import org.matrix.android.sdk.api.util.Cancelable
-import org.matrix.android.sdk.internal.task.TaskExecutor
-import org.matrix.android.sdk.internal.task.configureWith
 
 internal class DefaultReportingService @AssistedInject constructor(@Assisted private val roomId: String,
-                                                                   private val taskExecutor: TaskExecutor,
                                                                    private val reportContentTask: ReportContentTask
 ) : ReportingService {
 
@@ -34,13 +29,8 @@ internal class DefaultReportingService @AssistedInject constructor(@Assisted pri
         fun create(roomId: String): ReportingService
     }
 
-    override fun reportContent(eventId: String, score: Int, reason: String, callback: MatrixCallback<Unit>): Cancelable {
+    override suspend fun reportContent(eventId: String, score: Int, reason: String) {
         val params = ReportContentTask.Params(roomId, eventId, score, reason)
-
-        return reportContentTask
-                .configureWith(params) {
-                    this.callback = callback
-                }
-                .executeBy(taskExecutor)
+        reportContentTask.execute(params)
     }
 }
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 65d375e176aecf72b637274806328979452d2fe6..3463b26c8a1cf97dd7705e771d0d953162081e69 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
@@ -35,6 +35,7 @@ import org.matrix.android.sdk.internal.task.TaskExecutor
 import org.matrix.android.sdk.internal.task.configureWith
 import org.matrix.android.sdk.internal.task.launchToCallback
 import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
+import org.matrix.android.sdk.internal.util.awaitCallback
 
 internal class DefaultStateService @AssistedInject constructor(@Assisted private val roomId: String,
                                                                private val stateEventDataSource: StateEventDataSource,
@@ -132,23 +133,23 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
     override fun updateAvatar(avatarUri: Uri, fileName: String, callback: MatrixCallback<Unit>): Cancelable {
         return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, callback) {
             val response = fileUploader.uploadFromUri(avatarUri, fileName, "image/jpeg")
-            sendStateEvent(
-                    eventType = EventType.STATE_ROOM_AVATAR,
-                    body = mapOf("url" to response.contentUri),
-                    callback = callback,
-                    stateKey = null
-            )
+            awaitCallback<Unit> {
+                sendStateEvent(
+                        eventType = EventType.STATE_ROOM_AVATAR,
+                        body = mapOf("url" to response.contentUri),
+                        callback = it,
+                        stateKey = null
+                )
+            }
         }
     }
 
     override fun deleteAvatar(callback: MatrixCallback<Unit>): Cancelable {
-        return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, callback) {
-            sendStateEvent(
-                    eventType = EventType.STATE_ROOM_AVATAR,
-                    body = emptyMap(),
-                    callback = callback,
-                    stateKey = null
-            )
-        }
+        return sendStateEvent(
+                eventType = EventType.STATE_ROOM_AVATAR,
+                body = emptyMap(),
+                callback = callback,
+                stateKey = null
+        )
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/DefaultTagsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/DefaultTagsService.kt
index 932cb5d67eb7e44034631308ae9c5e08392848ab..d6c02f0a49b4d3297b4dcc95fac9412e2030800f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/DefaultTagsService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/tags/DefaultTagsService.kt
@@ -18,15 +18,10 @@ package org.matrix.android.sdk.internal.session.room.tags
 
 import com.squareup.inject.assisted.Assisted
 import com.squareup.inject.assisted.AssistedInject
-import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.session.room.tags.TagsService
-import org.matrix.android.sdk.api.util.Cancelable
-import org.matrix.android.sdk.internal.task.TaskExecutor
-import org.matrix.android.sdk.internal.task.configureWith
 
 internal class DefaultTagsService @AssistedInject constructor(
         @Assisted private val roomId: String,
-        private val taskExecutor: TaskExecutor,
         private val addTagToRoomTask: AddTagToRoomTask,
         private val deleteTagFromRoomTask: DeleteTagFromRoomTask
 ) : TagsService {
@@ -36,21 +31,13 @@ internal class DefaultTagsService @AssistedInject constructor(
         fun create(roomId: String): TagsService
     }
 
-    override fun addTag(tag: String, order: Double?, callback: MatrixCallback<Unit>): Cancelable {
+    override suspend fun addTag(tag: String, order: Double?) {
         val params = AddTagToRoomTask.Params(roomId, tag, order)
-        return addTagToRoomTask
-                .configureWith(params) {
-                    this.callback = callback
-                }
-                .executeBy(taskExecutor)
+        addTagToRoomTask.execute(params)
     }
 
-    override fun deleteTag(tag: String, callback: MatrixCallback<Unit>): Cancelable {
+    override suspend fun deleteTag(tag: String) {
         val params = DeleteTagFromRoomTask.Params(roomId, tag)
-        return deleteTagFromRoomTask
-                .configureWith(params) {
-                    this.callback = callback
-                }
-                .executeBy(taskExecutor)
+        deleteTagFromRoomTask.execute(params)
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt
index df2d238c05a7c7a5d3679d7ea98fdbd6d5b627a2..783aa53ddf725469e62e2bbf2f0c451b3f6dc50b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt
@@ -103,7 +103,7 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv
                     .sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING)
                     .findAll()
                     ?.mapNotNull { timelineEventMapper.map(it).takeIf { it.root.isImageMessage() || it.root.isVideoMessage() } }
-                    ?: emptyList()
+                    .orEmpty()
         }
     }
 }
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 2ba1eebe61ed13394841ac718e79169e7549c281..8033b0654da4a2b96f4beb40acec4dfc0cb04a3b 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
@@ -16,40 +16,31 @@
 
 package org.matrix.android.sdk.internal.session.search
 
-import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.session.search.SearchResult
 import org.matrix.android.sdk.api.session.search.SearchService
-import org.matrix.android.sdk.api.util.Cancelable
 import javax.inject.Inject
-import org.matrix.android.sdk.internal.task.TaskExecutor
-import org.matrix.android.sdk.internal.task.configureWith
 
 internal class DefaultSearchService @Inject constructor(
-        private val taskExecutor: TaskExecutor,
         private val searchTask: SearchTask
 ) : SearchService {
 
-    override fun search(searchTerm: String,
-                        roomId: String,
-                        nextBatch: String?,
-                        orderByRecent: Boolean,
-                        limit: Int,
-                        beforeLimit: Int,
-                        afterLimit: Int,
-                        includeProfile: Boolean,
-                        callback: MatrixCallback<SearchResult>): Cancelable {
-        return searchTask
-                .configureWith(SearchTask.Params(
-                        searchTerm = searchTerm,
-                        roomId = roomId,
-                        nextBatch = nextBatch,
-                        orderByRecent = orderByRecent,
-                        limit = limit,
-                        beforeLimit = beforeLimit,
-                        afterLimit = afterLimit,
-                        includeProfile = includeProfile
-                )) {
-                    this.callback = callback
-                }.executeBy(taskExecutor)
+    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,
+                roomId = roomId,
+                nextBatch = nextBatch,
+                orderByRecent = orderByRecent,
+                limit = limit,
+                beforeLimit = beforeLimit,
+                afterLimit = afterLimit,
+                includeProfile = includeProfile
+        ))
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/CryptoSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/CryptoSyncHandler.kt
index da28199f1b6a510d06c8af96fbd863ac086807dd..fc476a3dd69699ece2a6c0709084367f90880fd9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/CryptoSyncHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/CryptoSyncHandler.kt
@@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent
 import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
 import org.matrix.android.sdk.internal.crypto.MXEventDecryptionResult
 import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult
+import org.matrix.android.sdk.internal.crypto.model.event.OlmEventContent
 import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationService
 import org.matrix.android.sdk.internal.session.DefaultInitialSyncProgressService
 import org.matrix.android.sdk.internal.session.sync.model.SyncResponse
@@ -39,6 +40,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
         toDevice.events?.forEachIndexed { index, event ->
             initialSyncProgressService?.reportProgress(((index / total.toFloat()) * 100).toInt())
             // Decrypt event if necessary
+            Timber.i("## CRYPTO | To device event from ${event.senderId} of type:${event.type}")
             decryptToDeviceEvent(event, null)
             if (event.getClearType() == EventType.MESSAGE
                     && event.getClearContent()?.toModel<MessageContent>()?.msgType == "m.bad.encrypted") {
@@ -69,7 +71,12 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
                 result = cryptoService.decryptEvent(event, timelineId ?: "")
             } catch (exception: MXCryptoError) {
                 event.mCryptoError = (exception as? MXCryptoError.Base)?.errorType // setCryptoError(exception.cryptoError)
-                Timber.e("## CRYPTO | Failed to decrypt to device event: ${event.mCryptoError ?: exception}")
+                val senderKey = event.content.toModel<OlmEventContent>()?.senderKey ?: "<unknown sender key>"
+                // try to find device id to ease log reading
+                val deviceId = cryptoService.getCryptoDeviceInfo(event.senderId!!).firstOrNull {
+                    it.identityKey() == senderKey
+                 }?.deviceId ?: senderKey
+                Timber.e("## CRYPTO | Failed to decrypt to device event from ${event.senderId}|$deviceId reason:<${event.mCryptoError ?: exception}>")
             }
 
             if (null != result) {
@@ -80,6 +87,9 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService:
                         forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
                 )
                 return true
+            } else {
+                // should not happen
+                Timber.e("## CRYPTO | ERROR NULL DECRYPTION RESULT from ${event.senderId}")
             }
         }
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomTypingUsersHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomTypingUsersHandler.kt
index 1655e551f1149fffaa57d818deec94a553df40df..f4f3e6ce43714f8b113fe7f1e470d4f74925ad13 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomTypingUsersHandler.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomTypingUsersHandler.kt
@@ -28,7 +28,7 @@ internal class RoomTypingUsersHandler @Inject constructor(@UserId private val us
 
     fun handle(realm: Realm, roomId: String, ephemeralResult: RoomSyncHandler.EphemeralResult?) {
         val roomMemberHelper = RoomMemberHelper(realm, roomId)
-        val typingIds = ephemeralResult?.typingUserIds?.filter { it != userId } ?: emptyList()
+        val typingIds = ephemeralResult?.typingUserIds?.filter { it != userId }.orEmpty()
         val senderInfo = typingIds.map { userId ->
             val roomMemberSummaryEntity = roomMemberHelper.getLastRoomMember(userId)
             SenderInfo(
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 427a8896c9ea202ffe66a772cbc7c6f2fe06109e..77289f04b43a21238b7e715948bfebf5bce6464a 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
@@ -17,18 +17,21 @@
 package org.matrix.android.sdk.internal.session.sync
 
 import org.matrix.android.sdk.internal.network.NetworkConstants
+import org.matrix.android.sdk.internal.network.TimeOutInterceptor
 import org.matrix.android.sdk.internal.session.sync.model.SyncResponse
 import retrofit2.Call
 import retrofit2.http.GET
-import retrofit2.http.Headers
+import retrofit2.http.Header
 import retrofit2.http.QueryMap
 
 internal interface SyncAPI {
-
     /**
-     * Set all the timeouts to 1 minute
+     * Set all the timeouts to 1 minute by default
      */
-    @Headers("CONNECT_TIMEOUT:60000", "READ_TIMEOUT:60000", "WRITE_TIMEOUT:60000")
     @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "sync")
-    fun sync(@QueryMap params: Map<String, String>): Call<SyncResponse>
+    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
+    ): Call<SyncResponse>
 }
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 303bb454192c57afea70e0e4673ee5438dfbd3d5..b4fd6e7386ac6c0d0a803e0678ed7509513f20b9 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
@@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.sync
 import org.greenrobot.eventbus.EventBus
 import org.matrix.android.sdk.R
 import org.matrix.android.sdk.internal.di.UserId
+import org.matrix.android.sdk.internal.network.TimeOutInterceptor
 import org.matrix.android.sdk.internal.network.executeRequest
 import org.matrix.android.sdk.internal.session.DefaultInitialSyncProgressService
 import org.matrix.android.sdk.internal.session.filter.FilterRepository
@@ -78,8 +79,13 @@ internal class DefaultSyncTask @Inject constructor(
         // Maybe refresh the home server capabilities data we know
         getHomeServerCapabilitiesTask.execute(Unit)
 
+        val readTimeOut = (params.timeout + TIMEOUT_MARGIN).coerceAtLeast(TimeOutInterceptor.DEFAULT_LONG_TIMEOUT)
+
         val syncResponse = executeRequest<SyncResponse>(eventBus) {
-            apiCall = syncAPI.sync(requestParams)
+            apiCall = syncAPI.sync(
+                    params = requestParams,
+                    readTimeOut = readTimeOut
+            )
         }
         syncResponseHandler.handleResponse(syncResponse, token)
         if (isInitialSync) {
@@ -87,4 +93,8 @@ internal class DefaultSyncTask @Inject constructor(
         }
         Timber.v("Sync task finished on Thread: ${Thread.currentThread().name}")
     }
+
+    companion object {
+        private const val TIMEOUT_MARGIN: Long = 10_000
+    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/typing/DefaultTypingUsersTracker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/typing/DefaultTypingUsersTracker.kt
index 2b7ff2624a7fac28e77cb27e4bdb82fe793316ac..c5c3fc4b59525920c2679e001b688146de6f4e66 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/typing/DefaultTypingUsersTracker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/typing/DefaultTypingUsersTracker.kt
@@ -37,6 +37,6 @@ internal class DefaultTypingUsersTracker @Inject constructor() : TypingUsersTrac
     }
 
     override fun getTypingUsers(roomId: String): List<SenderInfo> {
-        return typingUsers[roomId] ?: emptyList()
+        return typingUsers[roomId].orEmpty()
     }
 }
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 d2eb7a14ef72b1348e9653f97a803e0e80eb3e29..17409569150f97a462ad72fee0087dd8d9691e1b 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
@@ -19,10 +19,13 @@ package org.matrix.android.sdk.internal.session.user
 import androidx.lifecycle.LiveData
 import androidx.paging.PagedList
 import org.matrix.android.sdk.api.MatrixCallback
+import org.matrix.android.sdk.api.session.profile.ProfileService
 import org.matrix.android.sdk.api.session.user.UserService
 import org.matrix.android.sdk.api.session.user.model.User
 import org.matrix.android.sdk.api.util.Cancelable
+import org.matrix.android.sdk.api.util.JsonDict
 import org.matrix.android.sdk.api.util.Optional
+import org.matrix.android.sdk.internal.session.profile.GetProfileInfoTask
 import org.matrix.android.sdk.internal.session.user.accountdata.UpdateIgnoredUserIdsTask
 import org.matrix.android.sdk.internal.session.user.model.SearchUserTask
 import org.matrix.android.sdk.internal.task.TaskExecutor
@@ -32,12 +35,40 @@ 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,
                                                       private val taskExecutor: TaskExecutor) : UserService {
 
     override fun getUser(userId: String): User? {
         return userDataSource.getUser(userId)
     }
 
+    override fun resolveUser(userId: String, callback: MatrixCallback<User>) {
+        val known = getUser(userId)
+        if (known != null) {
+            callback.onSuccess(known)
+        } else {
+            val params = GetProfileInfoTask.Params(userId)
+            getProfileInfoTask
+                    .configureWith(params) {
+                        this.callback = object : MatrixCallback<JsonDict> {
+                            override fun onSuccess(data: JsonDict) {
+                                callback.onSuccess(
+                                        User(
+                                                userId,
+                                                data[ProfileService.DISPLAY_NAME_KEY] as? String,
+                                                data[ProfileService.AVATAR_URL_KEY] as? String)
+                                )
+                            }
+
+                            override fun onFailure(failure: Throwable) {
+                                callback.onFailure(failure)
+                            }
+                        }
+                    }
+                    .executeBy(taskExecutor)
+        }
+    }
+
     override fun getUserLive(userId: String): LiveData<Optional<User>> {
         return userDataSource.getUserLive(userId)
     }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserStore.kt
index 5c8cbd08b1a009839db3714ac7b62832e1af0543..c030872dade4d93dfe35cb60e7d10dd49f36b2ae 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserStore.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserStore.kt
@@ -18,12 +18,15 @@ package org.matrix.android.sdk.internal.session.user
 
 import com.zhuinden.monarchy.Monarchy
 import org.matrix.android.sdk.internal.database.model.UserEntity
+import org.matrix.android.sdk.internal.database.query.where
 import org.matrix.android.sdk.internal.di.SessionDatabase
 import org.matrix.android.sdk.internal.util.awaitTransaction
 import javax.inject.Inject
 
 internal interface UserStore {
     suspend fun createOrUpdate(userId: String, displayName: String? = null, avatarUrl: String? = null)
+    suspend fun updateAvatar(userId: String, avatarUrl: String? = null)
+    suspend fun updateDisplayName(userId: String, displayName: String? = null)
 }
 
 internal class RealmUserStore @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : UserStore {
@@ -34,4 +37,20 @@ internal class RealmUserStore @Inject constructor(@SessionDatabase private val m
             it.insertOrUpdate(userEntity)
         }
     }
+
+    override suspend fun updateAvatar(userId: String, avatarUrl: String?) {
+        monarchy.awaitTransaction { realm ->
+            UserEntity.where(realm, userId).findFirst()?.let {
+                it.avatarUrl = avatarUrl ?: ""
+            }
+        }
+    }
+
+    override suspend fun updateDisplayName(userId: String, displayName: String?) {
+        monarchy.awaitTransaction { realm ->
+            UserEntity.where(realm, userId).findFirst()?.let {
+                it.displayName = displayName ?: ""
+            }
+        }
+    }
 }
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 22bdd2c6e44d0b58a88cd78effd19921555eb589..329903f15b5dbce1543720f9559ac6f5b43eb999 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
@@ -138,7 +138,7 @@ internal class WidgetManager @Inject constructor(private val integrationManager:
     ): LiveData<List<Widget>> {
         val widgetsAccountData = accountDataDataSource.getLiveAccountDataEvent(UserAccountDataTypes.TYPE_WIDGETS)
         return Transformations.map(widgetsAccountData) {
-            it.getOrNull()?.mapToWidgets(widgetTypes, excludedTypes) ?: emptyList()
+            it.getOrNull()?.mapToWidgets(widgetTypes, excludedTypes).orEmpty()
         }
     }
 
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 32997e20642e10cbf48ce32a6913bf0b7fa5172c..ecfbe311f1d8d3742922b8ae2e9805c65bd521b9 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
@@ -50,8 +50,6 @@ fun convertFromUTF8(s: String): String {
     }
 }
 
-fun String.withoutPrefix(prefix: String) = if (startsWith(prefix)) substringAfter(prefix) else this
-
 /**
  * Returns whether a string contains an occurrence of another, as a standalone word, regardless of case.
  *
diff --git a/matrix-sdk-android/src/main/res/values-ca/strings.xml b/matrix-sdk-android/src/main/res/values-ca/strings.xml
index 2dc2206c8c92c7f5a6844995868b9faaa766ef5d..8ba8c9acfd33b94484fdb765981611c1bd917dc4 100644
--- a/matrix-sdk-android/src/main/res/values-ca/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-ca/strings.xml
@@ -1,79 +1,217 @@
-<?xml version='1.0' encoding='UTF-8'?>
+<?xml version="1.0" encoding="utf-8"?>
 <resources>
     <string name="summary_message">%1$s: %2$s</string>
     <string name="summary_user_sent_image">%1$s ha enviat una imatge.</string>
-
-    <string name="notice_room_leave">%1s ha sortit</string>
-    <string name="notice_room_join">%1s ha entrat</string>
+    <string name="notice_room_leave">%1$s ha marxat de la sala</string>
+    <string name="notice_room_join">%1$s s\'ha unit a la sala</string>
     <string name="medium_phone_number">Número de telèfon</string>
-
     <string name="medium_email">Correu electrònic</string>
-    <string name="encrypted_message">Missatge encriptat</string>
-
-    <string name="notice_room_invite_no_invitee">la invitació de %s</string>
+    <string name="encrypted_message">Missatge xifrat</string>
+    <string name="notice_room_invite_no_invitee">invitació de %s</string>
     <string name="notice_room_invite">%1$s ha convidat a %2$s</string>
-    <string name="notice_room_invite_you">%1$s us ha convidat</string>
+    <string name="notice_room_invite_you">%1$s t\'ha convidat</string>
     <string name="notice_room_reject">%1$s ha rebutjat la invitació</string>
-    <string name="notice_room_kick">%1$s ha fet fora a %2$s</string>
-
-
-    <string name="notice_display_name_changed_from">%1$s ha canviat el seu nom visible de %2$s a %3$s</string>
-    <string name="notice_display_name_removed">%1$s ha eliminat el seu nom visible (%2$s)</string>
+    <string name="notice_room_kick">%1$s ha expulsat %2$s</string>
+    <string name="notice_display_name_changed_from">%1$s ha canviat el seu nom de visualització de %2$s a %3$s</string>
+    <string name="notice_display_name_removed">%1$s ha eliminat el seu nom de visualització (era %2$s)</string>
     <string name="notice_room_topic_changed">%1$s ha canviat el tema a: %2$s</string>
     <string name="notice_room_name_changed">%1$s ha canviat el nom de la sala a: %2$s</string>
-    <string name="notice_answered_call">%s ha contestat la trucada.</string>
+    <string name="notice_answered_call">%s ha respost a la trucada.</string>
     <string name="notice_ended_call">%s ha finalitzat la trucada.</string>
-    <string name="notice_room_visibility_invited">tots el membres de la sala, des del punt en què són convidats.</string>
-    <string name="notice_room_visibility_shared">tots els membres de la sala.</string>
+    <string name="notice_room_visibility_invited">tots el participants de la sala, des de que són convidats.</string>
+    <string name="notice_room_visibility_shared">tots els participants de la sala.</string>
     <string name="notice_room_visibility_unknown">desconegut (%s).</string>
-    <string name="notice_end_to_end">%1$s ha activat l\'encriptació d\'extrem a extrem (%2$s)</string>
-
+    <string name="notice_end_to_end">%1$s ha activat el xifrat d\'extrem a extrem (%2$s)</string>
     <string name="notice_requested_voip_conference">%1$s ha sol·licitat una conferència VoIP</string>
-    <string name="notice_room_unban">%1$s ha readmès a %2$s</string>
-    <string name="notice_room_ban">%1$s ha vetat a %2$s</string>
+    <string name="notice_room_unban">%1$s ha tret el veto a %2$s</string>
+    <string name="notice_room_ban">%1$s ha vetat %2$s</string>
     <string name="notice_room_withdraw">%1$s ha retirat la invitació de %2$s</string>
     <string name="notice_avatar_url_changed">%1$s ha canviat el seu avatar</string>
-    <string name="notice_made_future_room_visibility">%1$s ha permès a %2$s veure l\'historial que es generi a partir d\'ara</string>
-    <string name="notice_room_visibility_joined">tots els membres de la sala, des del punt en què hi entrin.</string>
+    <string name="notice_made_future_room_visibility">%1$s ha establert la visibilitat de l\'historial futur de la sala a %2$s</string>
+    <string name="notice_room_visibility_joined">tots els participants de la sala, des de que s\'hi uneixen.</string>
     <string name="notice_room_visibility_world_readable">qualsevol.</string>
     <string name="notice_voip_started">S\'ha iniciat la conferència VoIP</string>
-    <string name="notice_voip_finished">S\'ha finalitzat la conferència de veu IP</string>
-
-    <string name="notice_avatar_changed_too">(s\'ha canviat també l\'avatar)</string>
+    <string name="notice_voip_finished">Ha finalitzat la conferència VoIP</string>
+    <string name="notice_avatar_changed_too">(també ha canviat l\'avatar)</string>
     <string name="notice_room_name_removed">%1$s ha eliminat el nom de la sala</string>
     <string name="notice_room_topic_removed">%1$s ha eliminat el tema de la sala</string>
     <string name="notice_profile_change_redacted">%1$s ha actualitzat el seu perfil %2$s</string>
-    <string name="notice_room_third_party_invite">%1$s ha enviat una invitació a %2$s per a entrar a la sala</string>
-    <string name="notice_room_third_party_registered_invite">%1$s ha acceptat la invitació per a %2$s</string>
-
-    <string name="notice_crypto_unable_to_decrypt">** No s\'ha pogut desencriptar: %s **</string>
+    <string name="notice_room_third_party_invite">%1$s ha enviat una invitació a %2$s perquè s\'uneixi a la sala</string>
+    <string name="notice_room_third_party_registered_invite">%1$s ha acceptat la invitació de %2$s</string>
+    <string name="notice_crypto_unable_to_decrypt">** No s\'ha pogut desxifrar: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">El dispositiu del remitent no ens ha enviat les claus per aquest missatge.</string>
-
     <string name="could_not_redact">No s\'ha pogut redactar</string>
     <string name="unable_to_send_message">No s\'ha pogut enviar el missatge</string>
-
     <string name="message_failed_to_upload">No s\'ha pogut pujar la imatge</string>
-
-    <string name="network_error">S\'ha produït un error de xarxa</string>
-    <string name="matrix_error">S\'ha produït un error de Matrix</string>
-
-    <string name="room_error_join_failed_empty_room">Actualment no es pot tornar a entrar a una sala buida.</string>
-
-    <string name="notice_display_name_set">%1$s a canviat el seu nom visible a %2$s</string>
-    <string name="notice_placed_video_call">%s ha iniciat una trucada de vídeo.</string>
-    <string name="notice_placed_voice_call">%s ha iniciat una trucada de veu.</string>
-
+    <string name="network_error">Error de xarxa</string>
+    <string name="matrix_error">Error de Matrix</string>
+    <string name="room_error_join_failed_empty_room">Ara per ara no és possible tornar a unir-se a una sala buida.</string>
+    <string name="notice_display_name_set">%1$s a canviat el seu nom de visualització a %2$s</string>
+    <string name="notice_placed_video_call">%s ha realitzat una videotrucada.</string>
+    <string name="notice_placed_voice_call">%s ha realitzat una trucada de veu.</string>
     <!-- Room display name -->
-    <string name="room_displayname_invite_from">Convidat per %s</string>
-    <string name="room_displayname_room_invite">Convideu a la sala</string>
+    <string name="room_displayname_invite_from">Invitació de %s</string>
+    <string name="room_displayname_room_invite">Convida a la sala</string>
     <string name="room_displayname_two_members">%1$s i %2$s</string>
     <string name="room_displayname_empty_room">Sala buida</string>
     <plurals name="room_displayname_three_and_more_members">
         <item quantity="one">%1$s i 1 altre</item>
         <item quantity="other">%1$s i %2$d altres</item>
     </plurals>
-
-
     <string name="summary_user_sent_sticker">%1$s ha enviat un adhesiu.</string>
-
-</resources>
+    <string name="notice_direct_room_update">%s s\'ha actualitzat aquí.</string>
+    <string name="notice_direct_room_update_by_you">Ho has actualitzat aquí.</string>
+    <string name="key_verification_request_fallback_message">%s està sol·licitant la verificació de la teva clau, però el teu client no admet la verificació de clau des del xat. Hauràs d\'utilitzar la verificació de claus heretada per fer la verificació.</string>
+    <string name="notice_end_to_end_unknown_algorithm_by_you">Has activat el xifrat d\'extrem a extrem (algorisme %1$s no reconegut).</string>
+    <string name="notice_end_to_end_unknown_algorithm">%1$s ha activat el xifrat d\'extrem a extrem (algorisme %2$s no reconegut).</string>
+    <string name="notice_end_to_end_ok_by_you">Has activat el xifrat d\'extrem a extrem.</string>
+    <string name="notice_end_to_end_ok">%1$s ha activat el xifrat d\'extrem a extrem.</string>
+    <string name="notice_direct_room_guest_access_forbidden_by_you">Has impedit que els convidats es puguin unir a la sala.</string>
+    <string name="notice_direct_room_guest_access_forbidden">%1$s ha impedit que els convidats es puguin unir a la sala.</string>
+    <string name="notice_room_guest_access_forbidden_by_you">Has impedit que els convidats es puguin unir a la sala.</string>
+    <string name="notice_room_guest_access_forbidden">%1$s ha impedit que els convidats es puguin unir a la sala.</string>
+    <string name="notice_direct_room_guest_access_can_join_by_you">Has permès que els convidats s\'uneixin aquí.</string>
+    <string name="notice_direct_room_guest_access_can_join">%1$s ha permès que els convidats s\'uneixin aquí.</string>
+    <string name="notice_room_guest_access_can_join_by_you">Has permès que els convidats s\'uneixin a la sala.</string>
+    <string name="notice_room_guest_access_can_join">%1$s ha permès que els convidats s\'uneixin a la sala.</string>
+    <string name="notice_room_canonical_alias_unset_by_you">Has eliminat l\'adreça principal d\'aquesta sala.</string>
+    <string name="notice_room_canonical_alias_unset">%1$s ha eliminat l\'adreça principal d\'aquesta sala.</string>
+    <string name="notice_room_canonical_alias_set_by_you">Has establert l\'adreça principal d\'aquesta sala a %1$s.</string>
+    <string name="notice_room_canonical_alias_set">%1$s ha establert l\'adreça principal d\'aquesta sala a %2$s.</string>
+    <string name="notice_room_aliases_added_and_removed_by_you">Has afegit %1$s i has eliminat %2$s d\'aquesta sala (adreces).</string>
+    <string name="notice_room_aliases_added_and_removed">%1$s ha afegit %2$s i ha eliminat %3$s d\'aquesta sala (adreces).</string>
+    <plurals name="notice_room_aliases_removed_by_you">
+        <item quantity="one">Has eliminat l\'adreça %1$s d\'aquesta sala.</item>
+        <item quantity="other">Has eliminat les adreces %1$s d\'aquesta sala.</item>
+    </plurals>
+    <plurals name="notice_room_aliases_removed">
+        <item quantity="one">%1$s ha eliminat l\'adreça %2$s d\'aquesta sala.</item>
+        <item quantity="other">%1$s ha eliminat les adreces %3$s d\'aquesta sala.</item>
+    </plurals>
+    <plurals name="notice_room_aliases_added_by_you">
+        <item quantity="one">Has afegit l\'adreça %1$s a aquesta sala.</item>
+        <item quantity="other">Has afegit les adreces %1$s a aquesta sala.</item>
+    </plurals>
+    <plurals name="notice_room_aliases_added">
+        <item quantity="one">%1$s ha afegit l\'adreça %2$s a aquesta sala.</item>
+        <item quantity="other">%1$s ha afegit les adreces %2$s a aquesta sala.</item>
+    </plurals>
+    <string name="notice_room_third_party_revoked_invite_with_reason_by_you">Has revocat la invitació de %1$s perquè s\'uneixi a la sala. Motiu: %2$s</string>
+    <string name="notice_room_third_party_revoked_invite_with_reason">%1$s ha revocat la invitació de %2$s perquè s\'uneixi a la sala. Motiu: %3$s</string>
+    <string name="notice_direct_room_third_party_revoked_invite_by_you">Has revocat la invitació de %1$s</string>
+    <string name="notice_direct_room_third_party_revoked_invite">%1$s ha revocat la invitació de %2$s</string>
+    <string name="notice_room_third_party_revoked_invite_by_you">Has revocat la invitació de %1$s perquè s\'uneixi a la sala</string>
+    <string name="notice_room_third_party_revoked_invite">%1$s ha revocat la invitació de %2$s perquè s\'uneixi a la sala</string>
+    <string name="notice_room_withdraw_with_reason_by_you">Has retirat la invitació de %1$s. Motiu: %2$s</string>
+    <string name="notice_room_withdraw_with_reason">%1$s ha retirat la invitació de %2$s. Motiu: %3$s</string>
+    <string name="notice_room_third_party_registered_invite_with_reason_by_you">Has acceptat la invitació de %1$s. Motiu: %2$s</string>
+    <string name="notice_room_third_party_registered_invite_with_reason">%1$s ha acceptat la invitació de %2$s. Motiu: %3$s</string>
+    <string name="notice_room_third_party_invite_with_reason_by_you">Has enviat una invitació a %1$s perquè s\'uneixi a la sala. Motiu: %2$s</string>
+    <string name="notice_room_third_party_invite_with_reason">%1$s ha enviat una invitació a %2$s perquè s\'uneixi a la sala. Motiu: %3$s</string>
+    <string name="notice_room_ban_with_reason_by_you">Has vetat %1$s. Motiu: %2$s</string>
+    <string name="notice_room_ban_with_reason">%1$s ha vetat %2$s. Motiu: %3$s</string>
+    <string name="notice_room_unban_with_reason_by_you">Has tret el veto a %1$s. Motiu: %2$s</string>
+    <string name="notice_room_unban_with_reason">%1$s ha tret el veto a %2$s. Motiu: %3$s</string>
+    <string name="notice_room_ban_by_you">Has vetat %1$s</string>
+    <string name="notice_room_leave_with_reason_by_you">Has marxat de la sala. Motiu: %1$s</string>
+    <string name="notice_room_leave_with_reason">%1$s ha marxat de la sala. Motiu: %2$s</string>
+    <string name="notice_direct_room_leave_by_you">Has marxat de la sala</string>
+    <string name="notice_direct_room_leave">%1$s ha marxat de la sala</string>
+    <string name="notice_room_leave_by_you">Has marxat de la sala</string>
+    <string name="notice_room_kick_by_you">Has expulsat %1$s</string>
+    <string name="notice_room_kick_with_reason_by_you">Has expulsat %1$s. Motiu: %2$s</string>
+    <string name="notice_room_kick_with_reason">%1$s ha expulsat %2$s. Motiu: %3$s</string>
+    <string name="notice_room_reject_with_reason_by_you">Has rebutjat la invitació. Motiu: %1$s</string>
+    <string name="notice_room_reject_with_reason">%1$s ha rebutjat la invitació. Motiu: %2$s</string>
+    <string name="notice_direct_room_leave_with_reason_by_you">Has marxat. Motiu: %1$s</string>
+    <string name="notice_direct_room_leave_with_reason">%1$s ha marxat. Motiu: %2$s</string>
+    <string name="notice_direct_room_join_with_reason_by_you">T\'has unit. Motiu: %1$s</string>
+    <string name="notice_direct_room_join_with_reason">%1$s s\'ha unit. Motiu: %2$s</string>
+    <string name="notice_room_join_with_reason_by_you">T\'has unit a la sala. Motiu: %1$s</string>
+    <string name="notice_room_join_with_reason">%1$s s\'ha unit a la sala. Motiu: %2$s</string>
+    <string name="notice_room_invite_you_with_reason">%1$s t\'ha convidat. Motiu: %2$s</string>
+    <string name="notice_room_invite_with_reason_by_you">Has convidat %1$s. Motiu: %2$s</string>
+    <string name="notice_room_invite_with_reason">%1$s ha convidat %2$s. Motiu: %3$s</string>
+    <string name="notice_room_invite_no_invitee_with_reason_by_you">La teva invitació. Motiu: %1$s</string>
+    <string name="notice_room_invite_no_invitee_with_reason">la invitació de %1$s. Motiu: %2$s</string>
+    <string name="clear_timeline_send_queue">Esborra la cua d\'enviament</string>
+    <string name="event_status_sending_message">Enviant missatge…</string>
+    <string name="initial_sync_start_importing_account_data">Sincronització inicial:
+\nImportant dades del compte</string>
+    <string name="initial_sync_start_importing_account_groups">Sincronització inicial:
+\nImportant comunitats</string>
+    <string name="initial_sync_start_importing_account_left_rooms">Sincronització inicial:
+\nImportant sales que deixat</string>
+    <string name="initial_sync_start_importing_account">Sincronització inicial:
+\nImportant compte…</string>
+    <string name="initial_sync_start_importing_account_crypto">Sincronització inicial:
+\nImportant xifrat</string>
+    <string name="initial_sync_start_importing_account_rooms">Sincronització inicial:
+\nImportant sales</string>
+    <string name="initial_sync_start_importing_account_invited_rooms">Sincronització inicial:
+\nImportant sales on hi estàs convidat</string>
+    <string name="initial_sync_start_importing_account_joined_rooms">Sincronització inicial:
+\nImportant sales on hi estàs unit</string>
+    <string name="notice_power_level_diff">%1$s de %2$s a %3$s</string>
+    <string name="notice_power_level_changed">%1$s ha canviat el nivell d\'autoritat de %2$s.</string>
+    <string name="notice_power_level_changed_by_you">Has canviat el nivell d\'autoritat de %1$s.</string>
+    <string name="power_level_custom_no_value">Personalitzat</string>
+    <string name="power_level_custom">Personalitzat (%1$d)</string>
+    <string name="power_level_default">Predeterminat</string>
+    <string name="power_level_moderator">Moderador</string>
+    <string name="power_level_admin">Administrador</string>
+    <string name="notice_widget_modified_by_you">Has modificat el giny %1$s</string>
+    <string name="notice_widget_modified">%1$s ha modificat el giny %2$s</string>
+    <string name="notice_widget_removed_by_you">Has eliminat el giny %1$s</string>
+    <string name="notice_widget_removed">%1$s ha eliminat el giny %2$s</string>
+    <string name="notice_widget_added_by_you">Has afegit el giny %1$s</string>
+    <string name="notice_widget_added">%1$s ha afegit el giny %2$s</string>
+    <string name="notice_room_third_party_registered_invite_by_you">Has acceptat la invitació de %1$s</string>
+    <string name="notice_direct_room_third_party_invite_by_you">Has convidat a %1$s</string>
+    <string name="notice_direct_room_third_party_invite">%1$s ha convidat a %2$s</string>
+    <string name="notice_room_third_party_invite_by_you">Has enviat una invitació a %1$s perquè s\'uneixi a la sala</string>
+    <string name="notice_profile_change_redacted_by_you">Has actualitzat el teu perfil %1$s</string>
+    <string name="notice_event_redacted_by_with_reason">Missatge eliminat per %1$s [motiu: %2$s]</string>
+    <string name="notice_event_redacted_with_reason">Missatge eliminat [motiu: %1$s]</string>
+    <string name="notice_event_redacted_by">Missatge eliminat per %1$s</string>
+    <string name="notice_event_redacted">Missatge eliminat</string>
+    <string name="notice_room_avatar_removed_by_you">Has eliminat l\'avatar de la sala</string>
+    <string name="notice_room_avatar_removed">%1$s ha eliminat l\'avatar de la sala</string>
+    <string name="notice_room_topic_removed_by_you">Has eliminat el tema de la sala</string>
+    <string name="notice_room_name_removed_by_you">Has eliminat el nom de la sala</string>
+    <string name="notice_requested_voip_conference_by_you">Has sol·licitat una conferència VoIP</string>
+    <string name="notice_room_update_by_you">Has actualitzat aquesta sala.</string>
+    <string name="notice_room_update">%s ha actualitzat aquesta sala.</string>
+    <string name="notice_end_to_end_by_you">Has activat el xifrat d\'extrem a extrem (%1$s)</string>
+    <string name="notice_made_future_direct_room_visibility_by_you">Has establert la visibilitat dels missatges futurs a %1$s</string>
+    <string name="notice_made_future_direct_room_visibility">%1$s ha establert la visibilitat dels missatges futurs a %2$s</string>
+    <string name="notice_made_future_room_visibility_by_you">Has establert la visibilitat de l\'historial futur de la sala a %1$s</string>
+    <string name="notice_ended_call_by_you">Has finalitzat la trucada.</string>
+    <string name="notice_answered_call_by_you">Has respost a la trucada.</string>
+    <string name="notice_call_candidates_by_you">Has enviat dades per configurar la trucada.</string>
+    <string name="notice_call_candidates">%s ha enviat dades per configurar la trucada.</string>
+    <string name="notice_placed_voice_call_by_you">Has realitzat una trucada de veu.</string>
+    <string name="notice_placed_video_call_by_you">Has realitzat una videotrucada.</string>
+    <string name="notice_room_name_changed_by_you">Has canviat el nom de la sala a: %1$s</string>
+    <string name="notice_room_avatar_changed_by_you">Has canviat l\'avatar de la sala</string>
+    <string name="notice_room_avatar_changed">%1$s ha canviat l\'avatar de la sala</string>
+    <string name="notice_room_topic_changed_by_you">Has canviat el tema a: %1$s</string>
+    <string name="notice_display_name_removed_by_you">Has eliminat el teu nom de visualització (era %1$s)</string>
+    <string name="notice_display_name_changed_from_by_you">Has canviat el teu nom de visualització de %1$s a %2$s</string>
+    <string name="notice_display_name_set_by_you">Has canviat el teu nom de visualització a %1$s</string>
+    <string name="notice_avatar_url_changed_by_you">Has canviat el teu avatar</string>
+    <string name="notice_room_withdraw_by_you">Has retirat la invitació de %1$s</string>
+    <string name="notice_room_unban_by_you">Has tret el veto a %1$s</string>
+    <string name="notice_room_reject_by_you">Has rebutjat la invitació</string>
+    <string name="notice_direct_room_created_by_you">Has creat la discussió</string>
+    <string name="notice_direct_room_created">%1$s ha creat la discussió</string>
+    <string name="notice_direct_room_join_by_you">T\'has unit</string>
+    <string name="notice_direct_room_join">%1$s s\'ha unit</string>
+    <string name="notice_room_join_by_you">T\'has unit a la sala</string>
+    <string name="notice_room_invite_by_you">Has convidat a %1$s</string>
+    <string name="notice_room_created_by_you">Has creat la sala</string>
+    <string name="notice_room_created">%1$s ha creat la sala</string>
+    <string name="notice_room_invite_no_invitee_by_you">La teva invitació</string>
+    <string name="summary_you_sent_sticker">Has enviat un adhesiu.</string>
+    <string name="summary_you_sent_image">Has enviat una imatge.</string>
+</resources>
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/res/values-es/strings.xml b/matrix-sdk-android/src/main/res/values-es/strings.xml
index e2d09c7857013b9958ced084f62f1a9a9392c130..3648ca3a72d8f7b396dfdc7e93ee01b06080e59a 100644
--- a/matrix-sdk-android/src/main/res/values-es/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-es/strings.xml
@@ -1,9 +1,7 @@
-<?xml version='1.0' encoding='UTF-8'?>
+<?xml version="1.0" encoding="utf-8"?>
 <resources>
-
     <string name="summary_message">%1$s: %2$s</string>
     <string name="summary_user_sent_image">%1$s envió una imagen.</string>
-
     <string name="notice_room_invite_no_invitee">la invitación de %s</string>
     <string name="notice_room_invite">%1$s invitó a %2$s</string>
     <string name="notice_room_invite_you">%1$s te ha invitado</string>
@@ -30,61 +28,44 @@
     <string name="notice_room_visibility_shared">todos los miembros de la sala.</string>
     <string name="notice_room_visibility_world_readable">todos.</string>
     <string name="notice_room_visibility_unknown">desconocido (%s).</string>
-    <string name="notice_end_to_end">%1$s activó el cifrado de extremo a extremo (%2$s)</string>
-
+    <string name="notice_end_to_end">%1$s ha activado la encriptación de Extremo-a-Extremo (%2$s)</string>
     <string name="notice_requested_voip_conference">%1$s solicitó una conferencia de vozIP</string>
     <string name="notice_voip_started">conferencia de vozIP iniciada</string>
     <string name="notice_voip_finished">conferencia de vozIP finalizada</string>
-
     <string name="notice_avatar_changed_too">(el avatar también se cambió)</string>
     <string name="notice_room_name_removed">%1$s eliminó el nombre de la sala</string>
     <string name="notice_room_topic_removed">%1$s eliminó el tema de la sala</string>
     <string name="notice_profile_change_redacted">%1$s actualizó su perfil %2$s</string>
     <string name="notice_room_third_party_invite">%1$s invitó a %2$s a unirse a la sala</string>
     <string name="notice_room_third_party_registered_invite">%1$s aceptó la invitación para %2$s</string>
-
     <string name="notice_crypto_unable_to_decrypt">** No es posible descifrar: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">El dispositivo emisor no nos ha enviado las claves para este mensaje.</string>
-
     <!-- Room Screen -->
     <string name="could_not_redact">No se pudo redactar</string>
     <string name="unable_to_send_message">No es posible enviar el mensaje</string>
-
     <string name="message_failed_to_upload">No se pudo cargar la imagen</string>
-
     <!-- general errors -->
     <string name="network_error">Error de red</string>
     <string name="matrix_error">Error de Matrix</string>
-
     <!-- Home Screen -->
-
     <!-- Last seen time -->
-
     <!-- call events -->
-
     <!-- room error messages -->
     <string name="room_error_join_failed_empty_room">Actualmente no es posible volver a unirse a una sala vacía.</string>
-
-    <string name="encrypted_message">Mensaje cifrado</string>
-
+    <string name="encrypted_message">Mensaje encriptado</string>
     <!-- medium friendly name -->
     <string name="medium_email">Dirección de correo electrónico</string>
     <string name="medium_phone_number">Número telefónico</string>
-
     <string name="summary_user_sent_sticker">%1$s envió una pegatina.</string>
-
     <!-- Room display name -->
     <string name="room_displayname_invite_from">Invitación de %s</string>
     <string name="room_displayname_room_invite">Invitación a Sala</string>
     <string name="room_displayname_two_members">%1$s y %2$s</string>
     <string name="room_displayname_empty_room">Sala vacía</string>
-
     <plurals name="room_displayname_three_and_more_members">
         <item quantity="one">%1$s y 1 otro</item>
         <item quantity="other">%1$s y %2$d otros</item>
     </plurals>
-
-
     <string name="notice_event_redacted">Mensaje eliminado</string>
     <string name="notice_event_redacted_by">Mensaje eliminado por %1$s</string>
     <string name="notice_event_redacted_with_reason">Mensaje eliminado [motivo: %1$s]</string>
@@ -98,10 +79,8 @@
 \nImportando Comunidades</string>
     <string name="initial_sync_start_importing_account_data">Sincronización Inicial:
 \nImportando Datos de la Cuenta</string>
-
     <string name="event_status_sending_message">Enviando mensaje…</string>
     <string name="clear_timeline_send_queue">Borrar cola de envío</string>
-
     <string name="notice_room_invite_with_reason">%1$s ha invitado a %2$s. Razón: %3$s</string>
     <string name="notice_room_invite_you_with_reason">%1$s te ha invitado. Razón: %2$s</string>
     <string name="notice_room_join_with_reason">%1$s se ha unido. Razón: %2$s</string>
@@ -111,9 +90,7 @@
     <string name="notice_room_ban_with_reason">%1$s ha baneado a %2$s. Razón: %3$s</string>
     <string name="notice_room_third_party_registered_invite_with_reason">%1$s ha aceptado la invitación para %2$s. Razón: %3$s</string>
     <string name="notice_room_canonical_alias_unset">%1$s ha eliminado la dirección principal para esta sala.</string>
-
     <string name="notice_room_update">%s ha actualizado la sala.</string>
-
     <string name="initial_sync_start_importing_account_crypto">Sincronización Inicial:
 \nImportando criptografía</string>
     <string name="initial_sync_start_importing_account_joined_rooms">Sincronización Inicial:
@@ -127,32 +104,25 @@
     <string name="notice_room_third_party_invite_with_reason">%1$s envió una invitación a %2$s para que se una a la sala. Razón: %3$s</string>
     <string name="notice_room_third_party_revoked_invite_with_reason">%1$s revocó la invitación de %2$s para unirse a la sala. Razón: %3$s</string>
     <string name="notice_room_withdraw_with_reason">%1$s ha retirado la invitación de %2$s. Razón: %3$s</string>
-
     <plurals name="notice_room_aliases_added">
         <item quantity="one">%1$s ha añadido %2$s como alias de esta sala.</item>
         <item quantity="other">%1$s ha añadido %2$s como alias de esta sala.</item>
     </plurals>
-
     <plurals name="notice_room_aliases_removed">
-        <item quantity="one">%1$s ha quitado %2$s como alias de esta habitación.</item>
-        <item quantity="other">%1$s ha quitado %2$s como alias de esta habitación.</item>
+        <item quantity="one">%1$s ha quitado %2$s como alias de esta sala.</item>
+        <item quantity="other">%1$s ha quitado %2$s como alias de esta sala.</item>
     </plurals>
-
     <string name="notice_room_canonical_alias_set">%1$s ha establecido la dirección principal de esta sala a %2$s.</string>
     <string name="notice_room_guest_access_can_join">%1$s ha permitido que los invitados se unan a la sala.</string>
     <string name="notice_room_guest_access_forbidden">%1$s ha impedido que los invitados se unan a la sala.</string>
-
     <string name="notice_end_to_end_ok">%1$s ha activado la encriptación extremo a extremo.</string>
     <string name="notice_end_to_end_unknown_algorithm">%1$s ha activado la encriptación de extremo a extremo (algoritmo no reconocido %2$s).</string>
-
     <string name="key_verification_request_fallback_message">%s solicita verificar su clave, pero su cliente no soporta la verificación de la clave en chat. Necesitará usar la verificación de claves clásica para poder verificar las claves.</string>
-
     <string name="summary_you_sent_image">Enviaste una imagen.</string>
     <string name="summary_you_sent_sticker">Enviaste un sticker.</string>
-
     <string name="notice_room_invite_no_invitee_by_you">Tu invitación</string>
-    <string name="notice_room_created">%1$s creó la habitación</string>
-    <string name="notice_room_created_by_you">Tu creaste la habitación</string>
+    <string name="notice_room_created">%1$s creó la sala</string>
+    <string name="notice_room_created_by_you">Creaste la sala</string>
     <string name="notice_room_invite_by_you">Invitaste a %1$s</string>
     <string name="notice_room_join_by_you">Te uniste a la Sala</string>
     <string name="notice_room_leave_by_you">Dejaste la Sala</string>
@@ -167,8 +137,8 @@
     <string name="notice_display_name_removed_by_you">Quitaste tu nombre para mostrar (era %1$s)</string>
     <string name="notice_room_topic_changed_by_you">Cambiaste el tema a: %1$s</string>
     <string name="notice_room_avatar_changed">%1$s cambió el avatar de la sala</string>
-    <string name="notice_room_avatar_changed_by_you">Cambiaste el avatar de la habitación</string>
-    <string name="notice_room_name_changed_by_you">Cambiaste el nombre de la habitación a: %1$s</string>
+    <string name="notice_room_avatar_changed_by_you">Cambiaste el avatar de la sala</string>
+    <string name="notice_room_name_changed_by_you">Cambiaste el nombre de la sala a: %1$s</string>
     <string name="notice_placed_video_call_by_you">Hiciste una videollamada.</string>
     <string name="notice_placed_voice_call_by_you">Hiciste una llamada de voz.</string>
     <string name="notice_call_candidates">%s envió datos para configurar la llamada.</string>
@@ -176,40 +146,35 @@
     <string name="notice_answered_call_by_you">Respondiste la llamada.</string>
     <string name="notice_ended_call_by_you">Terminaste la llamada.</string>
     <string name="notice_made_future_room_visibility_by_you">Hiciste visible el futuro historial de la %1$s</string>
-    <string name="notice_end_to_end_by_you">Activó el cifrado de un extremo a otro (%1$s)</string>
-    <string name="notice_room_update_by_you">Has mejorado esta habitación.</string>
-
+    <string name="notice_end_to_end_by_you">Has activado la encriptación de Extremo-a-Extremo (%1$s)</string>
+    <string name="notice_room_update_by_you">Has actualizado esta sala.</string>
     <string name="notice_requested_voip_conference_by_you">Solicitaste una conferencia de VoIP</string>
     <string name="notice_room_name_removed_by_you">Quitaste el nombre de la sala</string>
     <string name="notice_room_topic_removed_by_you">Quitaste el tema de la sala</string>
-    <string name="notice_room_avatar_removed">%1$s eliminó el avatar de la habitación</string>
-    <string name="notice_room_avatar_removed_by_you">Quitaste el avatar de la habitación</string>
+    <string name="notice_room_avatar_removed">%1$s eliminó el avatar de la sala</string>
+    <string name="notice_room_avatar_removed_by_you">Quitaste el avatar de la sala</string>
     <string name="notice_profile_change_redacted_by_you">Actualizaste tu perfil %1$s</string>
     <string name="notice_room_third_party_invite_by_you">Enviaste una invitación a %1$s para unirse a la sala</string>
     <string name="notice_room_third_party_revoked_invite_by_you">Revocaste la invitación para que %1$s se una a la sala</string>
     <string name="notice_room_third_party_registered_invite_by_you">Aceptaste la invitación para %1$s</string>
-
     <string name="notice_widget_added">%1$s agrego el widget %2$s</string>
     <string name="notice_widget_added_by_you">Agregaste el widget %1$s</string>
     <string name="notice_widget_removed">%1$s eliminó el widget %2$s</string>
     <string name="notice_widget_removed_by_you">Quitaste el widget %1$s</string>
     <string name="notice_widget_modified">%1$s modifico el widget %2$s</string>
     <string name="notice_widget_modified_by_you">Modificaste el widget %1$s</string>
-
     <string name="power_level_admin">Administrador</string>
     <string name="power_level_moderator">Moderador</string>
     <string name="power_level_default">Por defecto</string>
     <string name="power_level_custom">Personalizado (%1$d)</string>
     <string name="power_level_custom_no_value">Personalizado</string>
-
     <string name="notice_power_level_changed_by_you">Cambiaste el nivel de potencia de %1$s.</string>
     <string name="notice_power_level_changed">%1$s cambió el nivel de potencia de %2$s.</string>
     <string name="notice_power_level_diff">%1$s de %2$s a %3$s</string>
-
     <string name="notice_room_invite_no_invitee_with_reason_by_you">Tu invitación. Razón: %1$s</string>
-    <string name="notice_room_invite_with_reason_by_you">"nvitaste a %1$s.  Razón: %2$s"</string>
-    <string name="notice_room_join_with_reason_by_you">Te uniste a la habitación. Razón: %1$s</string>
-    <string name="notice_room_leave_with_reason_by_you">Dejaste la habitación. Razón: %1$s</string>
+    <string name="notice_room_invite_with_reason_by_you">Invitaste a %1$s. Razón: %2$s</string>
+    <string name="notice_room_join_with_reason_by_you">Te uniste a la sala. Razón: %1$s</string>
+    <string name="notice_room_leave_with_reason_by_you">Dejaste la sala. Razón: %1$s</string>
     <string name="notice_room_reject_with_reason_by_you">Rechazaste la invitación. Razón: %1$s</string>
     <string name="notice_room_kick_with_reason_by_you">Pateaste a %1$s. Motivo: %2$s</string>
     <string name="notice_room_unban_with_reason_by_you">Has desactivado a %1$s. Motivo: %2$s</string>
@@ -218,27 +183,42 @@
     <string name="notice_room_third_party_revoked_invite_with_reason_by_you">Revocaste la invitación para que %1$s se una a la sala. Motivo: %2$s</string>
     <string name="notice_room_third_party_registered_invite_with_reason_by_you">Aceptaste la invitación para %1$s. Motivo: %2$s</string>
     <string name="notice_room_withdraw_with_reason_by_you">Retiró la invitación de %1$s\'s. Motivo: %2$s</string>
-
     <plurals name="notice_room_aliases_added_by_you">
         <item quantity="one">Agregaste %1$s como dirección para esta sala.</item>
         <item quantity="other">Agregaste %1$s como direcciones para esta sala.</item>
     </plurals>
-
     <plurals name="notice_room_aliases_removed_by_you">
         <item quantity="one">Quitaste %1$s como dirección para esta sala.</item>
         <item quantity="other">Quitaste %1$s como direcciones para esta sala.</item>
     </plurals>
-
-    <string name="notice_room_aliases_added_and_removed">"%1$s agregó %2$s  y eliminó %3$s como direcciones para esta sala."</string>
+    <string name="notice_room_aliases_added_and_removed">%1$s añadió %2$s y eliminó %3$s como alias para esta sala.</string>
     <string name="notice_room_aliases_added_and_removed_by_you">Agregaste %1$s y quitaste %2$s como direcciones para esta sala.</string>
-
     <string name="notice_room_canonical_alias_set_by_you">Estableciste la dirección principal de esta sala en %1$s.</string>
     <string name="notice_room_canonical_alias_unset_by_you">Quitaste la dirección principal de esta sala.</string>
-
     <string name="notice_room_guest_access_can_join_by_you">Ha permitido que los invitados se unan a la sala.</string>
     <string name="notice_room_guest_access_forbidden_by_you">Ha impedido que los invitados se unan a la sala.</string>
-
-    <string name="notice_end_to_end_ok_by_you">Activó el cifrado de extremo a extremo.</string>
-    <string name="notice_end_to_end_unknown_algorithm_by_you">Activó el cifrado de un extremo a otro (algoritmo %1$s no reconocido).</string>
-
-</resources>
+    <string name="notice_end_to_end_ok_by_you">Tu has activado la encriptación de Extremo-a-Extremo.</string>
+    <string name="notice_end_to_end_unknown_algorithm_by_you">Has activado la encriptación de Extremo-a-Extremo (algoritmo %1$s no reconocido).</string>
+    <string name="notice_direct_room_guest_access_forbidden_by_you">Has impedido que invitados se unan a la sala.</string>
+    <string name="notice_direct_room_guest_access_can_join_by_you">Has permitido a invitados unirse aquí.</string>
+    <string name="notice_direct_room_leave_with_reason_by_you">Te has ido. Razón: %1$s</string>
+    <string name="notice_direct_room_third_party_revoked_invite_by_you">Has revocado la invitación de %1$s</string>
+    <string name="notice_direct_room_third_party_invite_by_you">Has invitado a %1$s</string>
+    <string name="notice_direct_room_update_by_you">Has actualizado aquí.</string>
+    <string name="notice_made_future_direct_room_visibility_by_you">Has hecho futuros mensajes visibles a %1$s</string>
+    <string name="notice_direct_room_leave_by_you">Te saliste de la sala</string>
+    <string name="notice_direct_room_join_by_you">Te uniste</string>
+    <string name="notice_direct_room_created_by_you">Creaste la conversación</string>
+    <string name="notice_direct_room_guest_access_forbidden">%1$s ha impedido que invitados se unan a la sala.</string>
+    <string name="notice_direct_room_guest_access_can_join">%1$s ha permitido a invitados a unirse aquí.</string>
+    <string name="notice_direct_room_leave_with_reason">%1$s se ha ido. Razón: %2$s</string>
+    <string name="notice_direct_room_join_with_reason_by_you">Tu te has unido. Razón: %1$s</string>
+    <string name="notice_direct_room_join_with_reason">%1$s se ha unido. Razón: %2$s</string>
+    <string name="notice_direct_room_third_party_revoked_invite">%1$s ha revocado la invitación de %2$s</string>
+    <string name="notice_direct_room_third_party_invite">%1$s ha invitado %2$s</string>
+    <string name="notice_direct_room_update">%s ha actualizado aquí.</string>
+    <string name="notice_made_future_direct_room_visibility">%1$s ha hecho futuros mensajes visibles a %2$s</string>
+    <string name="notice_direct_room_leave">%1$s ha salido de la sala</string>
+    <string name="notice_direct_room_join">%1$s se ha unido</string>
+    <string name="notice_direct_room_created">%1$s ha creado la conversación</string>
+</resources>
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/res/values-fa/strings.xml b/matrix-sdk-android/src/main/res/values-fa/strings.xml
index 042fda7ddde185f4385e211374bcd378230c3217..11a786f5ac7f4b0c82bac195039ce3a25b6cbae5 100644
--- a/matrix-sdk-android/src/main/res/values-fa/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-fa/strings.xml
@@ -181,8 +181,8 @@
         <item quantity="other">نشانی‌های %1$s را به این اتاق افزودید.</item>
     </plurals>
     <plurals name="notice_room_aliases_removed_by_you">
-        <item quantity="one">نشانی %1$s ار از این اتاق برداشتید.</item>
-        <item quantity="other">نشانی‌های %1$s ار از این اتاق برداشتید.</item>
+        <item quantity="one">نشانی %1$s را از این اتاق برداشتید.</item>
+        <item quantity="other">نشانی‌های %1$s را از این اتاق برداشتید.</item>
     </plurals>
     <string name="notice_room_aliases_added_and_removed_by_you">نشانی %1$s ار افزوده و %2$s را از این اتاق برداشتید.</string>
     <string name="notice_room_canonical_alias_set_by_you">نشانی اصلی این اتاق را به %1$s تنظیم کردید.</string>
diff --git a/matrix-sdk-android/src/main/res/values-hu/strings.xml b/matrix-sdk-android/src/main/res/values-hu/strings.xml
index 4aade76c553416485f5bf25c21f1ced3beff29f4..49238ee8ff15e865f77b8026585f82fd7fa8ada6 100644
--- a/matrix-sdk-android/src/main/res/values-hu/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-hu/strings.xml
@@ -22,10 +22,10 @@
     <string name="notice_placed_voice_call">%s hanghívást indított.</string>
     <string name="notice_answered_call">%s fogadta a hívást.</string>
     <string name="notice_ended_call">%s befejezte a hívást.</string>
-    <string name="notice_made_future_room_visibility">%1$s láthatóvá tette a jövőbeli előzményeket %2$s számára</string>
-    <string name="notice_room_visibility_invited">az összes szobatag, onnantól, hogy meg lettek hívva.</string>
-    <string name="notice_room_visibility_joined">az összes szobatag, onnantól, hogy csatlakoztak.</string>
-    <string name="notice_room_visibility_shared">az összes szobatag.</string>
+    <string name="notice_made_future_room_visibility">%1$s láthatóvá tette a jövőbeli előzményeket %2$s</string>
+    <string name="notice_room_visibility_invited">a szoba összes tagja számára, a meghívásuk időpontjától kezdve.</string>
+    <string name="notice_room_visibility_joined">a szoba összes tagja számára, a csatlakozásuk időpontjától kezdve.</string>
+    <string name="notice_room_visibility_shared">az összes szobatag számára.</string>
     <string name="notice_room_visibility_world_readable">bárki.</string>
     <string name="notice_room_visibility_unknown">ismeretlen (%s).</string>
     <string name="notice_end_to_end">%1$s bekapcsolta a végpontok közötti titkosítást (%2$s)</string>
@@ -139,4 +139,40 @@
     <string name="notice_room_created_by_you">Létrehoztad a szobát</string>
     <string name="summary_you_sent_sticker">Matricát küldtél.</string>
     <string name="summary_you_sent_image">Képet küldtél.</string>
+    <string name="power_level_custom_no_value">Saját</string>
+    <string name="power_level_custom">Saját (%1$d)</string>
+    <string name="power_level_default">Alapértelmezett</string>
+    <string name="power_level_moderator">Moderátor</string>
+    <string name="power_level_admin">Admin</string>
+    <string name="notice_widget_modified_by_you">Ön megváltoztatta a %1$s kisalkalmazást</string>
+    <string name="notice_widget_modified">%1$s megváltoztatta a %2$s kisalkalmazást</string>
+    <string name="notice_widget_removed_by_you">Ön eltávolította a %1$s kisalkalmazást</string>
+    <string name="notice_widget_removed">%1$s eltávolította a %2$s kisalkalmazást</string>
+    <string name="notice_widget_added_by_you">Ön hozzáadott egy %1$s kisalkalmazást</string>
+    <string name="notice_widget_added">%1$s hozzáadott egy %2$s kisalkalmazást</string>
+    <string name="notice_room_third_party_registered_invite_by_you">Ön elfogadta a meghívót ehhez: %1$s</string>
+    <string name="notice_direct_room_third_party_revoked_invite_by_you">Ön visszavonta %1$s felhasználó meghívóját</string>
+    <string name="notice_direct_room_third_party_revoked_invite">%1$s visszavonta %2$s felhasználó meghívóját</string>
+    <string name="notice_room_third_party_revoked_invite_by_you">Ön visszavonta %1$s felhasználó meghívóját</string>
+    <string name="notice_direct_room_third_party_invite_by_you">Ön meghívta %1$s felhasználót</string>
+    <string name="notice_direct_room_third_party_invite">%1$s meghívta %2$s felhasználót</string>
+    <string name="notice_room_third_party_invite_by_you">Ön meghívót küldött %1$s felhasználónak, hogy csatlakozzon a szobához</string>
+    <string name="notice_profile_change_redacted_by_you">Ön frissítette a saját profilját %1$s</string>
+    <string name="notice_room_avatar_removed_by_you">Ön eltávolította a szoba képét</string>
+    <string name="notice_room_avatar_removed">%1$s eltávolította a szoba képét</string>
+    <string name="notice_room_topic_removed_by_you">Ön eltávolította a szoba témáját</string>
+    <string name="notice_room_name_removed_by_you">Ön eltávolította a szoba nevét</string>
+    <string name="notice_requested_voip_conference_by_you">Ön videókonferencia kezdeményezését kérte</string>
+    <string name="notice_direct_room_update_by_you">Ön frissítette ezt a szobát.</string>
+    <string name="notice_direct_room_update">%s frissítette a szobát.</string>
+    <string name="notice_room_update_by_you">Ön frissítette ezt a szobát.</string>
+    <string name="notice_end_to_end_by_you">Ön bekapcsolta a végpontok közötti titkosítást (%1$s)</string>
+    <string name="notice_made_future_direct_room_visibility_by_you">Ön elérhetővé tette a jövőbeni üzeneteket %1$s</string>
+    <string name="notice_made_future_room_visibility_by_you">Ön elérhetővé tette a jövőbeni üzeneteket %1$s</string>
+    <string name="notice_made_future_direct_room_visibility">%1$s elérhetővé tette a jövőbeni üzeneteket %2$s</string>
+    <string name="notice_room_name_changed_by_you">Ön megváltoztatta a szoba nevét erre: %1$s</string>
+    <string name="notice_display_name_removed_by_you">Ön eltávolította a saját megjelenített nevét (%1$s volt)</string>
+    <string name="notice_display_name_changed_from_by_you">Ön megváltoztatta a saját megjelenítési nevét erről: %1$s, erre: %2$s</string>
+    <string name="notice_display_name_set_by_you">Ön beállította a saját megjelenítési nevét erre: %1$s</string>
+    <string name="notice_room_invite_no_invitee_by_you">Az ön meghívása</string>
 </resources>
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/res/values-it/strings_sas.xml b/matrix-sdk-android/src/main/res/values-it/strings_sas.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b66c22bc6bc72029912ccb2d5e2bfe2bfcb6d01e
--- /dev/null
+++ b/matrix-sdk-android/src/main/res/values-it/strings_sas.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- Generated file, do not edit -->
+    <string name="verification_emoji_dog">Cane</string>
+    <string name="verification_emoji_cat">Gatto</string>
+    <string name="verification_emoji_lion">Leone</string>
+    <string name="verification_emoji_horse">Cavallo</string>
+    <string name="verification_emoji_unicorn">Unicorno</string>
+    <string name="verification_emoji_pig">Maiale</string>
+    <string name="verification_emoji_elephant">Elefante</string>
+    <string name="verification_emoji_rabbit">Coniglio</string>
+    <string name="verification_emoji_panda">Panda</string>
+    <string name="verification_emoji_rooster">Gallo</string>
+    <string name="verification_emoji_penguin">Pinguino</string>
+    <string name="verification_emoji_turtle">Tartaruga</string>
+    <string name="verification_emoji_fish">Pesce</string>
+    <string name="verification_emoji_octopus">Polpo</string>
+    <string name="verification_emoji_butterfly">Farfalla</string>
+    <string name="verification_emoji_flower">Fiore</string>
+    <string name="verification_emoji_tree">Albero</string>
+    <string name="verification_emoji_cactus">Cactus</string>
+    <string name="verification_emoji_mushroom">Fungo</string>
+    <string name="verification_emoji_globe">Globo</string>
+    <string name="verification_emoji_moon">Luna</string>
+    <string name="verification_emoji_cloud">Nuvola</string>
+    <string name="verification_emoji_fire">Fuoco</string>
+    <string name="verification_emoji_banana">Banana</string>
+    <string name="verification_emoji_apple">Mela</string>
+    <string name="verification_emoji_strawberry">Fragola</string>
+    <string name="verification_emoji_corn">Mais</string>
+    <string name="verification_emoji_pizza">Pizza</string>
+    <string name="verification_emoji_cake">Torta</string>
+    <string name="verification_emoji_heart">Cuore</string>
+    <string name="verification_emoji_smiley">Faccina sorridente</string>
+    <string name="verification_emoji_robot">Robot</string>
+    <string name="verification_emoji_hat">Cappello</string>
+    <string name="verification_emoji_glasses">Occhiali</string>
+    <string name="verification_emoji_spanner">Chiave inglese</string>
+    <string name="verification_emoji_santa">Babbo Natale</string>
+    <string name="verification_emoji_thumbs_up">Pollice alzato</string>
+    <string name="verification_emoji_umbrella">Ombrello</string>
+    <string name="verification_emoji_hourglass">Clessidra</string>
+    <string name="verification_emoji_clock">Orologio</string>
+    <string name="verification_emoji_gift">Regalo</string>
+    <string name="verification_emoji_light_bulb">Lampadina</string>
+    <string name="verification_emoji_book">Libro</string>
+    <string name="verification_emoji_pencil">Matita</string>
+    <string name="verification_emoji_paperclip">Graffetta</string>
+    <string name="verification_emoji_scissors">Forbici</string>
+    <string name="verification_emoji_lock">Lucchetto</string>
+    <string name="verification_emoji_key">Chiave</string>
+    <string name="verification_emoji_hammer">Martello</string>
+    <string name="verification_emoji_telephone">Telefono</string>
+    <string name="verification_emoji_flag">Bandiera</string>
+    <string name="verification_emoji_train">Treno</string>
+    <string name="verification_emoji_bicycle">Bicicletta</string>
+    <string name="verification_emoji_aeroplane">Aeroplano</string>
+    <string name="verification_emoji_rocket">Razzo</string>
+    <string name="verification_emoji_trophy">Trofeo</string>
+    <string name="verification_emoji_ball">Palla</string>
+    <string name="verification_emoji_guitar">Chitarra</string>
+    <string name="verification_emoji_trumpet">Trombetta</string>
+    <string name="verification_emoji_bell">Campana</string>
+    <string name="verification_emoji_anchor">Ancora</string>
+    <string name="verification_emoji_headphones">Cuffie</string>
+    <string name="verification_emoji_folder">Cartella</string>
+    <string name="verification_emoji_pin">Puntina</string>
+</resources>
diff --git a/matrix-sdk-android/src/main/res/values-ja/strings.xml b/matrix-sdk-android/src/main/res/values-ja/strings.xml
index 366c743494b7286013e0f471d3721b6ee52858bb..add19edfaf0ffbd8f30ef6701fc6065e273e9f6a 100644
--- a/matrix-sdk-android/src/main/res/values-ja/strings.xml
+++ b/matrix-sdk-android/src/main/res/values-ja/strings.xml
@@ -1,10 +1,8 @@
-<?xml version='1.0' encoding='UTF-8'?>
+<?xml version="1.0" encoding="utf-8"?>
 <resources>
-
     <string name="summary_message">%1$s: %2$s</string>
     <string name="summary_user_sent_image">%1$sが画像を送信しました。</string>
     <string name="summary_user_sent_sticker">%1$sがスタンプを送信しました。</string>
-
     <string name="notice_room_invite_no_invitee">%sの招待</string>
     <string name="notice_room_invite">%1$sが%2$sを招待しました</string>
     <string name="notice_room_invite_you">%1$sがあなたを招待しました</string>
@@ -29,11 +27,9 @@
     <string name="room_displayname_room_invite">部屋への招待</string>
     <string name="room_displayname_two_members">%1$sと%2$s</string>
     <string name="room_displayname_empty_room">空の部屋</string>
-
     <plurals name="room_displayname_three_and_more_members">
         <item quantity="other">%1$sと他%2$d名</item>
     </plurals>
-
     <string name="notice_made_future_room_visibility">%1$sは、今後の部屋履歴を%2$sに表示させました</string>
     <string name="notice_room_visibility_invited">部屋のメンバー全員、招待された時点から。</string>
     <string name="notice_room_visibility_joined">部屋のメンバー全員、参加した時点から。</string>
@@ -41,34 +37,50 @@
     <string name="notice_room_visibility_world_readable">誰でも。</string>
     <string name="notice_room_visibility_unknown">不明 (%s)。</string>
     <string name="notice_end_to_end">%1$s がエンドツーエンド暗号化を有効にしました (%2$s)</string>
-
     <string name="notice_requested_voip_conference">%1$s がVoIP会議をリクエストしました</string>
     <string name="notice_voip_started">VoIP会議が開始されました</string>
     <string name="notice_voip_finished">VoIP会議が終了しました</string>
-
     <string name="notice_avatar_changed_too">(アバターも変更された)</string>
     <string name="notice_room_name_removed">%1$s が部屋名を削除しました</string>
     <string name="notice_room_topic_removed">%1$s がルームトピックを削除しました</string>
     <string name="notice_profile_change_redacted">%1$s がプロフィール %2$s を更新しました</string>
     <string name="notice_room_third_party_invite">%1$s は %2$s に部屋に参加するよう招待状を送りました</string>
     <string name="notice_room_third_party_registered_invite">%1$sは%2$sの招待を受け入れました</string>
-
     <string name="notice_crypto_unable_to_decrypt">** 解読できません: %s **</string>
     <string name="notice_crypto_error_unkwown_inbound_session_id">送信者の端末からこのメッセージのキーが送信されていません。</string>
-
     <string name="could_not_redact">修正できませんでした</string>
     <string name="unable_to_send_message">メッセージを送信できません</string>
-
     <string name="message_failed_to_upload">画像のアップロードに失敗しました</string>
-
     <string name="network_error">ネットワークエラー</string>
     <string name="matrix_error">Matrixエラー</string>
-
     <string name="room_error_join_failed_empty_room">現在空の部屋に再参加することはできません。</string>
-
     <string name="encrypted_message">暗号化されたメッセージ</string>
-
     <string name="medium_email">メールアドレス</string>
     <string name="medium_phone_number">電話番号</string>
-
-</resources>
+    <string name="notice_room_avatar_changed_by_you">ルームのアバターを変更しました</string>
+    <string name="notice_room_avatar_changed">%1$sがルームのアバターを変更しました</string>
+    <string name="notice_room_topic_changed_by_you">トピックを%1$sに変更しました</string>
+    <string name="notice_display_name_removed_by_you">表示名を削除しました(%1$sでした)</string>
+    <string name="notice_display_name_changed_from_by_you">表示名を%1$sから%2$sに変更しました</string>
+    <string name="notice_display_name_set_by_you">表示名を%1$sに設定しました</string>
+    <string name="notice_avatar_url_changed_by_you">アバターを変更しました</string>
+    <string name="notice_room_withdraw_by_you">%1$sの招待を取り下げました</string>
+    <string name="notice_room_ban_by_you">%1$sをBANしました</string>
+    <string name="notice_room_unban_by_you">%1$sのBANを解除しました</string>
+    <string name="notice_room_kick_by_you">%1$sを退出させました</string>
+    <string name="notice_room_reject_by_you">招待を拒否しました</string>
+    <string name="notice_direct_room_leave_by_you">ルームから退出しました</string>
+    <string name="notice_direct_room_leave">%1$sがルームから退出しました</string>
+    <string name="notice_room_leave_by_you">ルームから退出しました</string>
+    <string name="notice_direct_room_join_by_you">参加しました</string>
+    <string name="notice_direct_room_join">%1$sが参加しました</string>
+    <string name="notice_room_join_by_you">ルームに参加しました</string>
+    <string name="notice_room_invite_by_you">%1$sを招待しました</string>
+    <string name="notice_direct_room_created_by_you">ディスカッションを作成しました</string>
+    <string name="notice_direct_room_created">%1$sがディスカッションを作成しました</string>
+    <string name="notice_room_created_by_you">ルームを作成しました</string>
+    <string name="notice_room_created">%1$sがルームを作成しました</string>
+    <string name="notice_room_invite_no_invitee_by_you">招待</string>
+    <string name="summary_you_sent_sticker">ステッカーを送信しました。</string>
+    <string name="summary_you_sent_image">画像を送信しました。</string>
+</resources>
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/res/values/strings.xml b/matrix-sdk-android/src/main/res/values/strings.xml
index 27f083269fc113dc33f88b4164c47b95a227a747..f77cd3203d6593f0ec745214a9421f82e474b17b 100644
--- a/matrix-sdk-android/src/main/res/values/strings.xml
+++ b/matrix-sdk-android/src/main/res/values/strings.xml
@@ -72,6 +72,23 @@
     <string name="notice_room_update_by_you">You upgraded this room.</string>
     <string name="notice_direct_room_update">%s upgraded here.</string>
     <string name="notice_direct_room_update_by_you">You upgraded here.</string>
+    <string name="notice_room_server_acl_set_title">%s set the server ACLs for this room.</string>
+    <string name="notice_room_server_acl_set_title_by_you">You set the server ACLs for this room.</string>
+    <string name="notice_room_server_acl_set_banned">• Server matching %s are banned.</string>
+    <string name="notice_room_server_acl_set_allowed">• Server matching %s are allowed.</string>
+    <string name="notice_room_server_acl_set_ip_literals_allowed">• Server matching IP literals are allowed.</string>
+    <string name="notice_room_server_acl_set_ip_literals_not_allowed">• Server matching IP literals are banned.</string>
+
+    <string name="notice_room_server_acl_updated_title">%s changed the server ACLs for this room.</string>
+    <string name="notice_room_server_acl_updated_title_by_you">You changed the server ACLs for this room.</string>
+    <string name="notice_room_server_acl_updated_banned">• Server matching %s are now banned.</string>
+    <string name="notice_room_server_acl_updated_was_banned">• Server matching %s were removed from the ban list.</string>
+    <string name="notice_room_server_acl_updated_allowed">• Server matching %s are now allowed.</string>
+    <string name="notice_room_server_acl_updated_was_allowed">• Server matching %s were removed from the allowed list.</string>
+    <string name="notice_room_server_acl_updated_ip_literals_allowed">• Server matching IP literals are now allowed.</string>
+    <string name="notice_room_server_acl_updated_ip_literals_not_allowed">• Server matching IP literals are now banned.</string>
+    <string name="notice_room_server_acl_updated_no_change">No change.</string>
+    <string name="notice_room_server_acl_allow_is_empty">🎉 All servers are banned from participating! This room can no longer be used.</string>
 
     <string name="notice_requested_voip_conference">%1$s requested a VoIP conference</string>
     <string name="notice_requested_voip_conference_by_you">You requested a VoIP conference</string>
@@ -158,13 +175,22 @@
 
     <!-- The 2 parameters will be members' name -->
     <string name="room_displayname_two_members">%1$s and %2$s</string>
-
+    <!-- The 3 parameters will be members' name -->
+    <string name="room_displayname_3_members">%1$s, %2$s and %3$s</string>
+    <!-- The 4 parameters will be members' name -->
+    <string name="room_displayname_4_members">%1$s, %2$s, %3$s and %4$s</string>
+    <!-- The 3 first parameters will be members' name -->
+    <plurals name="room_displayname_four_and_more_members">
+        <item quantity="one">%1$s, %2$s, %3$s and %4$d other</item>
+        <item quantity="other">%1$s, %2$s, %3$s and %4$d others</item>
+    </plurals>
     <plurals name="room_displayname_three_and_more_members">
         <item quantity="one">%1$s and 1 other</item>
         <item quantity="other">%1$s and %2$d others</item>
     </plurals>
 
     <string name="room_displayname_empty_room">Empty room</string>
+    <string name="room_displayname_empty_room_was">Empty room (was %s)</string>
 
     <string name="initial_sync_start_importing_account">Initial Sync:\nImporting account…</string>
     <string name="initial_sync_start_importing_account_crypto">Initial Sync:\nImporting crypto</string>