From 9dc21cd6329f2c690cfbdd9ebd139d6ff4145a16 Mon Sep 17 00:00:00 2001
From: Benoit Marty <benoit@matrix.org>
Date: Mon, 30 Nov 2020 15:51:56 +0100
Subject: [PATCH] Import SDK 1.0.11 from Element Android

---
 matrix-sdk-android/build.gradle               |   6 +-
 .../android/sdk/account/ChangePasswordTest.kt |   4 +-
 .../sdk/account/DeactivateAccountTest.kt      |   4 +-
 .../android/sdk/common/CommonTestHelper.kt    |   9 +
 .../android/sdk/common/CryptoTestHelper.kt    |   4 +-
 .../internal/crypto/verification/SASTest.kt   |   6 +-
 .../sdk/session/search/SearchMessagesTest.kt  |  53 ++--
 .../interceptors/FormattedJsonHttpLogger.kt   |   8 +-
 .../android/sdk/api/auth/login/LoginWizard.kt |   2 +-
 .../android/sdk/api/extensions/Strings.kt     |   5 +
 .../sdk/api/pushrules/PushRuleService.kt      |  10 +-
 .../matrix/android/sdk/api/raw/RawService.kt  |  11 +-
 .../sdk/api/session/account/AccountService.kt |   7 +-
 .../verification/VerificationService.kt       |   2 +-
 .../sdk/api/session/events/model/EventType.kt |   1 +
 .../android/sdk/api/session/group/Group.kt    |   6 +-
 .../api/session/identity/IdentityService.kt   |  20 ++
 .../session/identity/IdentityServiceError.kt  |   1 +
 .../api/session/permalinks/MatrixLinkify.kt   |  16 +-
 .../api/session/permalinks/PermalinkParser.kt |   5 +-
 .../sdk/api/session/room/RoomService.kt       |  17 ++
 .../session/room/crypto/RoomCryptoService.kt  |   4 +-
 .../session/room/failure/CreateRoomFailure.kt |   5 +
 .../room/model/RoomServerAclContent.kt        |  59 +++++
 .../room/model/create/CreateRoomParams.kt     |  21 +-
 .../room/notification/RoomPushRuleService.kt  |   4 +-
 .../room/reporting/ReportingService.kt        |   5 +-
 .../sdk/api/session/room/send/DraftService.kt |   6 +-
 .../sdk/api/session/room/tags/TagsService.kt  |   7 +-
 .../sdk/api/session/search/SearchService.kt   |  21 +-
 .../sdk/api/session/user/UserService.kt       |   5 +
 .../sdk/internal/crypto/CryptoModule.kt       |   1 +
 .../internal/crypto/DefaultCryptoService.kt   |  12 +-
 .../sdk/internal/crypto/EventDecryptor.kt     |  18 +-
 .../crypto/IncomingGossipingRequestManager.kt |   7 +-
 .../sdk/internal/crypto/MXOlmDevice.kt        |   2 +-
 .../sdk/internal/crypto/SendGossipWorker.kt   |   2 +-
 .../EnsureOlmSessionsForDevicesAction.kt      |   4 +-
 .../algorithms/megolm/MXMegolmDecryption.kt   |  22 +-
 .../algorithms/megolm/MXMegolmEncryption.kt   |  33 ++-
 .../DefaultCrossSigningService.kt             |   3 +-
 .../crypto/crosssigning/UpdateTrustWorker.kt  |   4 +-
 .../crypto/store/db/RealmCryptoStore.kt       |  21 +-
 .../DefaultVerificationService.kt             |  15 +-
 .../SASDefaultVerificationTransaction.kt      |   5 +-
 .../sdk/internal/database/RealmKeysUtils.kt   |   3 +-
 .../SessionRealmConfigurationFactory.kt       |   1 +
 .../internal/network/TimeOutInterceptor.kt    |   3 +
 .../sdk/internal/raw/DefaultRawService.kt     |  29 +--
 .../session/account/DefaultAccountService.kt  |  23 +-
 .../internal/session/group/DefaultGroup.kt    |  11 +-
 .../internal/session/group/GroupFactory.kt    |   5 +-
 .../identity/DefaultIdentityService.kt        |  17 ++
 .../session/identity/IdentityModule.kt        |   5 +
 .../session/identity/data/IdentityData.kt     |   3 +-
 .../session/identity/data/IdentityStore.kt    |   2 +
 .../session/identity/db/IdentityDataEntity.kt |   3 +-
 .../identity/db/IdentityDataEntityQuery.kt    |   7 +
 .../session/identity/db/IdentityMapper.kt     |   3 +-
 .../session/identity/db/RealmIdentityStore.kt |   8 +
 .../db/RealmIdentityStoreMigration.kt         |  43 ++++
 .../notification/DefaultPushRuleService.kt    |  34 +--
 .../session/profile/DefaultProfileService.kt  |  12 +-
 .../sdk/internal/session/room/DefaultRoom.kt  |  12 +-
 .../session/room/DefaultRoomService.kt        |  30 +++
 .../session/room/RoomAvatarResolver.kt        |  15 +-
 .../room/alias/GetRoomIdByAliasTask.kt        |  13 +-
 .../session/room/create/CreateRoomBody.kt     |   4 +-
 .../room/create/CreateRoomBodyBuilder.kt      |   2 +-
 .../session/room/create/CreateRoomTask.kt     |  46 +++-
 .../session/room/draft/DefaultDraftService.kt |  14 +-
 .../membership/RoomDisplayNameResolver.kt     |  49 +++-
 .../room/membership/RoomMemberHelper.kt       |   4 +-
 .../DefaultRoomPushRuleService.kt             |  15 +-
 .../room/reporting/DefaultReportingService.kt |  14 +-
 .../session/room/state/DefaultStateService.kt |  29 +--
 .../session/room/tags/DefaultTagsService.kt   |  21 +-
 .../room/timeline/DefaultTimelineService.kt   |   2 +-
 .../session/search/DefaultSearchService.kt    |  45 ++--
 .../session/sync/CryptoSyncHandler.kt         |  12 +-
 .../session/sync/RoomTypingUsersHandler.kt    |   2 +-
 .../sdk/internal/session/sync/SyncAPI.kt      |  13 +-
 .../sdk/internal/session/sync/SyncTask.kt     |  12 +-
 .../typing/DefaultTypingUsersTracker.kt       |   2 +-
 .../session/user/DefaultUserService.kt        |  31 +++
 .../sdk/internal/session/user/UserStore.kt    |  19 ++
 .../internal/session/widgets/WidgetManager.kt |   2 +-
 .../android/sdk/internal/util/StringUtils.kt  |   2 -
 .../src/main/res/values-ca/strings.xml        | 234 ++++++++++++++----
 .../src/main/res/values-es/strings.xml        | 104 ++++----
 .../src/main/res/values-fa/strings.xml        |   4 +-
 .../src/main/res/values-hu/strings.xml        |  44 +++-
 .../src/main/res/values-it/strings_sas.xml    |  68 +++++
 .../src/main/res/values-ja/strings.xml        |  44 ++--
 .../src/main/res/values/strings.xml           |  28 ++-
 95 files changed, 1082 insertions(+), 549 deletions(-)
 create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomServerAclContent.kt
 create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt
 create mode 100644 matrix-sdk-android/src/main/res/values-it/strings_sas.xml

diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle
index 6ca21262..3d81c0db 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 ec5477f9..103b638c 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 a6fbfd9b..9996eef0 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 cbe4cca8..0e7088a6 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 1a9165ad..cbb22daf 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 75c7ad4d..a81f503e 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 7db159cd..ae300c93 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 5c03e8a8..630f6f1e 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 645fb55b..48705ee7 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 a17e65b8..e264843e 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 880a7be9..4da16626 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 4e24a170..19549a33 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 b05f0036..8915202f 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 65c6a1f1..2413786e 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 82dea81a..0a7f3ff0 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 a4186b5a..25c69e50 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 537104a0..aedb8137 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 72bb72cc..42fdb976 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 7f264c62..5e9f3e1e 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 dc47c81a..347a3bb5 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 b772225f..f30037e5 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 e7e6bacc..1251fd98 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 b0df2963..b4e2dc64 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 00000000..92078054
--- /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 892a8657..80e3741a 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 32d60335..eb822c68 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 0ccdfd1d..a444e234 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 116a60e3..a9481d71 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 3278c640..69fde61f 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 ef2eec43..bc1c9e57 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 2cfc4b73..ab85f979 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 a8580bab..a786ebd4 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 d3a3fd9f..ebd809f7 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 38488f1c..92b77288 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 97ae0b9d..4f94a27b 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 1a4d1136..c952602d 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 f0a34139..bcaa16f3 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 b05f2cd5..95b99c54 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 e0116fae..787d16de 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 e55cf371..fd431ce7 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 1871dba0..bcad448e 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 f28fe7d6..665d770e 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 72274aa7..6b83c4f7 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 7f027503..a92f5c5b 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 cb254eac..22a190c6 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 6c430e85..0e3a7a2c 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 3324520d..244fe343 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 6c604f23..724ec0dc 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 be01366e..3b0d7546 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 31a39d45..1165d211 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 01b57767..4f610fd8 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 31450763..653d2a69 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 20f8b7f8..c6fb3415 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 1bb57b47..7a39a333 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 0f04f2fe..54d35b34 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 3a905833..0e05224b 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 cc03465c..019289a8 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 062c28ea..5152e337 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 98207f1b..bf23c058 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 0352e9b9..2fa3fc0c 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 00000000..6081dbab
--- /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 217da269..e00d2ff2 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 8d092772..5265e4f1 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 1338df68..c7bb640f 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 d49c2f12..28656463 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 90ee99a9..99f9d364 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 8b011980..58a119cc 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 c30f11b9..13d403e2 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 632fcab7..79ff9db0 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 4f0aaf08..0fe9b0ba 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 92e16a35..93fbfb4d 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 7f3796c1..a7dfcfc9 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 7105a2cc..2a7c46bd 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 8797b0c7..67ae55c0 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 384c544e..cac87a9d 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 65d375e1..3463b26c 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 932cb5d6..d6c02f0a 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 df2d238c..783aa53d 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 2ba1eebe..8033b065 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 da28199f..fc476a3d 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 1655e551..f4f3e6ce 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 427a8896..77289f04 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 303bb454..b4fd6e73 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 2b7ff262..c5c3fc4b 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 d2eb7a14..17409569 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 5c8cbd08..c030872d 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 22bdd2c6..329903f1 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 32997e20..ecfbe311 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 2dc2206c..8ba8c9ac 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 e2d09c78..3648ca3a 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 042fda7d..11a786f5 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 4aade76c..49238ee8 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 00000000..b66c22bc
--- /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 366c7434..add19edf 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 27f08326..f77cd320 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>
-- 
GitLab