diff --git a/.idea/dictionaries/bmarty.xml b/.idea/dictionaries/bmarty.xml
index 16cc35cebe..4de90e9405 100644
--- a/.idea/dictionaries/bmarty.xml
+++ b/.idea/dictionaries/bmarty.xml
@@ -26,6 +26,7 @@
pkcs
previewable
previewables
+ pstn
riotx
signin
signout
diff --git a/CHANGES.md b/CHANGES.md
index 091b49791d..f84d182cc8 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -15,6 +15,7 @@ Bugfix 🐛:
- Fix crash after initial sync on Dendrite
- Fix crash reported by PlayStore (#2707)
- Ignore url override from credential if it is not valid (#2822)
+ - Fix crash when deactivating an account
Translations 🗣:
-
@@ -31,6 +32,7 @@ Test:
Other changes:
- New Dev Tools panel for developers
- Fix typos in CHANGES.md (#2811)
+ - Colors rework: first step: merge file `colors_riot.xml` to file `colors_riotx.xml` and rename the file to `colors.xml`
Changes in Element 1.0.17 (2021-02-09)
===================================================
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 78b9cb20ed..01c4f8ccb3 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,12 +43,13 @@ class DeactivateAccountTest : InstrumentedTest {
@Test
fun deactivateAccountTest() {
- val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false))
+ val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
// Deactivate the account
commonTestHelper.runBlockingTest {
session.deactivateAccount(
- object : UserInteractiveAuthInterceptor {
+ eraseAllData = false,
+ userInteractiveAuthInterceptor = object : UserInteractiveAuthInterceptor {
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation) {
promise.resume(
UserPasswordAuth(
@@ -58,7 +59,8 @@ class DeactivateAccountTest : InstrumentedTest {
)
)
}
- }, false)
+ }
+ )
}
// Try to login on the previous account, it will fail (M_USER_DEACTIVATED)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
index c06cdd9e23..e0ee9f36ba 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt
@@ -53,22 +53,24 @@ fun Throwable.isInvalidUIAAuth(): Boolean {
* Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible
*/
fun Throwable.toRegistrationFlowResponse(): RegistrationFlowResponse? {
- return if (this is Failure.OtherServerError && this.httpCode == 401) {
+ return if (this is Failure.OtherServerError && httpCode == 401) {
tryOrNull {
MoshiProvider.providesMoshi()
.adapter(RegistrationFlowResponse::class.java)
- .fromJson(this.errorBody)
+ .fromJson(errorBody)
}
- } else if (this is Failure.ServerError && this.httpCode == 401 && this.error.code == MatrixError.M_FORBIDDEN) {
+ } else if (this is Failure.ServerError && httpCode == 401 && error.code == MatrixError.M_FORBIDDEN) {
// This happens when the submission for this stage was bad (like bad password)
- if (this.error.session != null && this.error.flows != null) {
+ if (error.session != null && error.flows != null) {
RegistrationFlowResponse(
- flows = this.error.flows,
- session = this.error.session,
- completedStages = this.error.completedStages,
- params = this.error.params
+ flows = error.flows,
+ session = error.session,
+ completedStages = error.completedStages,
+ params = error.params
)
- } else null
+ } else {
+ null
+ }
} else {
null
}
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 eb327dfd56..1f28dbd8af 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt
@@ -27,7 +27,8 @@ interface AccountService {
* @param password Current password.
* @param newPassword New password
*/
- suspend fun changePassword(password: String, newPassword: String)
+ suspend fun changePassword(password: String,
+ newPassword: String)
/**
* Deactivate the account.
@@ -41,9 +42,10 @@ interface AccountService {
* be shared with any new or unregistered users, but registered users who already have access to these messages will still
* have access to their copy.
*
- * @param password the account password
* @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
+ * @param userInteractiveAuthInterceptor see [UserInteractiveAuthInterceptor]
*/
- suspend fun deactivateAccount(userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, eraseAllData: Boolean)
+ suspend fun deactivateAccount(eraseAllData: Boolean,
+ userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt
index c6bdcd19c7..dc67aa536a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt
@@ -16,12 +16,11 @@
package org.matrix.android.sdk.api.session.call
-import org.matrix.android.sdk.api.MatrixCallback
-import org.matrix.android.sdk.api.util.Cancelable
-
interface CallSignalingService {
- fun getTurnServer(callback: MatrixCallback): Cancelable
+ suspend fun getTurnServer(): TurnServerResponse
+
+ fun getPSTNProtocolChecker(): PSTNProtocolChecker
/**
* Create an outgoing call
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/PSTNProtocolChecker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/PSTNProtocolChecker.kt
new file mode 100644
index 0000000000..6627f62e24
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/PSTNProtocolChecker.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2021 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.session.call
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
+import org.matrix.android.sdk.internal.session.SessionScope
+import org.matrix.android.sdk.internal.session.thirdparty.GetThirdPartyProtocolsTask
+import org.matrix.android.sdk.internal.task.TaskExecutor
+import timber.log.Timber
+import java.util.concurrent.atomic.AtomicBoolean
+import javax.inject.Inject
+
+private const val PSTN_VECTOR_KEY = "im.vector.protocol.pstn"
+private const val PSTN_MATRIX_KEY = "m.protocol.pstn"
+
+/**
+ * This class is responsible for checking if the HS support the PSTN protocol.
+ * As long as the request succeed, it'll check only once by session.
+ */
+@SessionScope
+class PSTNProtocolChecker @Inject internal constructor(private val taskExecutor: TaskExecutor,
+ private val getThirdPartyProtocolsTask: GetThirdPartyProtocolsTask) {
+
+ interface Listener {
+ fun onPSTNSupportUpdated()
+ }
+
+ private var alreadyChecked = AtomicBoolean(false)
+
+ private val pstnSupportListeners = mutableListOf()
+
+ fun addListener(listener: Listener) {
+ pstnSupportListeners.add(listener)
+ }
+
+ fun removeListener(listener: Listener) {
+ pstnSupportListeners.remove(listener)
+ }
+
+ var supportedPSTNProtocol: String? = null
+ private set
+
+ fun checkForPSTNSupportIfNeeded() {
+ if (alreadyChecked.get()) return
+ taskExecutor.executorScope.checkForPSTNSupport()
+ }
+
+ private fun CoroutineScope.checkForPSTNSupport() = launch {
+ try {
+ supportedPSTNProtocol = getSupportedPSTN(3)
+ alreadyChecked.set(true)
+ if (supportedPSTNProtocol != null) {
+ pstnSupportListeners.forEach {
+ tryOrNull { it.onPSTNSupportUpdated() }
+ }
+ }
+ } catch (failure: Throwable) {
+ Timber.v("Fail to get supported PSTN, will check again next time.")
+ }
+ }
+
+ private suspend fun getSupportedPSTN(maxTries: Int): String? {
+ val thirdPartyProtocols: Map = try {
+ getThirdPartyProtocolsTask.execute(Unit)
+ } catch (failure: Throwable) {
+ if (maxTries == 1) {
+ throw failure
+ } else {
+ // Wait for 10s before trying again
+ delay(10_000L)
+ return getSupportedPSTN(maxTries - 1)
+ }
+ }
+ return when {
+ thirdPartyProtocols.containsKey(PSTN_VECTOR_KEY) -> PSTN_VECTOR_KEY
+ thirdPartyProtocols.containsKey(PSTN_MATRIX_KEY) -> PSTN_MATRIX_KEY
+ else -> null
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
index fa5ea359e8..eead9b4ab7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
@@ -56,8 +56,6 @@ interface CryptoService {
fun deleteDevice(deviceId: String, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, callback: MatrixCallback)
- fun deleteDeviceWithUserPassword(deviceId: String, authSession: String?, password: String, callback: MatrixCallback)
-
fun getCryptoVersion(context: Context, longFormat: Boolean): String
fun isCryptoEnabled(): Boolean
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt
index 1a0383cb22..da0866a5fd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt
@@ -16,14 +16,25 @@
package org.matrix.android.sdk.internal.auth.registration
+import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse
-import org.matrix.android.sdk.api.auth.UIABaseAuth
import timber.log.Timber
import kotlin.coroutines.suspendCoroutine
-internal suspend fun handleUIA(failure: Throwable, interceptor: UserInteractiveAuthInterceptor, retryBlock: suspend (UIABaseAuth) -> Unit): Boolean {
+/**
+ * Handle a UIA challenge
+ *
+ * @param failure the failure to handle
+ * @param interceptor see doc in [UserInteractiveAuthInterceptor]
+ * @param retryBlock called at the end of the process, in this block generally retry executing the task, with
+ * provided authUpdate
+ * @return true if UIA is handled without error
+ */
+internal suspend fun handleUIA(failure: Throwable,
+ interceptor: UserInteractiveAuthInterceptor,
+ retryBlock: suspend (UIABaseAuth) -> Unit): Boolean {
Timber.d("## UIA: check error ${failure.message}")
val flowResponse = failure.toRegistrationFlowResponse()
?: return false.also {
@@ -38,16 +49,16 @@ internal suspend fun handleUIA(failure: Throwable, interceptor: UserInteractiveA
suspendCoroutine { continuation ->
interceptor.performStage(flowResponse, (failure as? Failure.ServerError)?.error?.code, continuation)
}
- } catch (failure: Throwable) {
- Timber.w(failure, "## UIA: failed to participate")
+ } catch (failure2: Throwable) {
+ Timber.w(failure2, "## UIA: failed to participate")
return false
}
- Timber.d("## UIA: updated auth $authUpdate")
+ Timber.d("## UIA: updated auth")
return try {
retryBlock(authUpdate)
true
- } catch (failure: Throwable) {
- handleUIA(failure, interceptor, retryBlock)
+ } catch (failure3: Throwable) {
+ handleUIA(failure3, interceptor, retryBlock)
}
}
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 a786ebd4b2..e114f86a99 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
@@ -61,7 +61,6 @@ import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule
import org.matrix.android.sdk.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask
import org.matrix.android.sdk.internal.crypto.tasks.DefaultClaimOneTimeKeysForUsersDevice
import org.matrix.android.sdk.internal.crypto.tasks.DefaultDeleteDeviceTask
-import org.matrix.android.sdk.internal.crypto.tasks.DefaultDeleteDeviceWithUserPasswordTask
import org.matrix.android.sdk.internal.crypto.tasks.DefaultDownloadKeysForUsers
import org.matrix.android.sdk.internal.crypto.tasks.DefaultEncryptEventTask
import org.matrix.android.sdk.internal.crypto.tasks.DefaultGetDeviceInfoTask
@@ -75,7 +74,6 @@ import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadKeysTask
import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadSignaturesTask
import org.matrix.android.sdk.internal.crypto.tasks.DefaultUploadSigningKeysTask
import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask
-import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceWithUserPasswordTask
import org.matrix.android.sdk.internal.crypto.tasks.DownloadKeysForUsersTask
import org.matrix.android.sdk.internal.crypto.tasks.EncryptEventTask
import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask
@@ -240,9 +238,6 @@ internal abstract class CryptoModule {
@Binds
abstract fun bindClaimOneTimeKeysForUsersDeviceTask(task: DefaultClaimOneTimeKeysForUsersDevice): ClaimOneTimeKeysForUsersDeviceTask
- @Binds
- abstract fun bindDeleteDeviceWithUserPasswordTask(task: DefaultDeleteDeviceWithUserPasswordTask): DeleteDeviceWithUserPasswordTask
-
@Binds
abstract fun bindCrossSigningService(service: DefaultCrossSigningService): CrossSigningService
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 678bc9819f..67229a5eae 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
@@ -75,7 +75,6 @@ import org.matrix.android.sdk.internal.crypto.model.toRest
import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask
-import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceWithUserPasswordTask
import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask
import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask
import org.matrix.android.sdk.internal.crypto.tasks.SetDeviceNameTask
@@ -153,9 +152,8 @@ internal class DefaultCryptoService @Inject constructor(
// Repository
private val megolmEncryptionFactory: MXMegolmEncryptionFactory,
private val olmEncryptionFactory: MXOlmEncryptionFactory,
- private val deleteDeviceTask: DeleteDeviceTask,
- private val deleteDeviceWithUserPasswordTask: DeleteDeviceWithUserPasswordTask,
// Tasks
+ private val deleteDeviceTask: DeleteDeviceTask,
private val getDevicesTask: GetDevicesTask,
private val getDeviceInfoTask: GetDeviceInfoTask,
private val setDeviceNameTask: SetDeviceNameTask,
@@ -217,15 +215,6 @@ internal class DefaultCryptoService @Inject constructor(
.executeBy(taskExecutor)
}
- override fun deleteDeviceWithUserPassword(deviceId: String, authSession: String?, password: String, callback: MatrixCallback) {
- deleteDeviceWithUserPasswordTask
- .configureWith(DeleteDeviceWithUserPasswordTask.Params(deviceId, authSession, password)) {
- this.executionThread = TaskThread.CRYPTO
- this.callback = callback
- }
- .executeBy(taskExecutor)
- }
-
override fun getCryptoVersion(context: Context, longFormat: Boolean): String {
return if (longFormat) olmManager.getDetailedVersion(context) else olmManager.version
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt
index ff25ac0f66..61596bb5b6 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceTask.kt
@@ -47,12 +47,16 @@ internal class DefaultDeleteDeviceTask @Inject constructor(
}
} catch (throwable: Throwable) {
if (params.userInteractiveAuthInterceptor == null
- || !handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth ->
- execute(params.copy(userAuthParam = auth))
- }
+ || !handleUIA(
+ failure = throwable,
+ interceptor = params.userInteractiveAuthInterceptor,
+ retryBlock = { authUpdate ->
+ execute(params.copy(userAuthParam = authUpdate))
+ }
+ )
) {
Timber.d("## UIA: propagate failure")
- throw throwable
+ throw throwable
}
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt
deleted file mode 100644
index dc0077425e..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/DeleteDeviceWithUserPasswordTask.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.tasks
-
-import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
-import org.matrix.android.sdk.internal.crypto.api.CryptoApi
-import org.matrix.android.sdk.internal.crypto.model.rest.DeleteDeviceParams
-import org.matrix.android.sdk.api.auth.UserPasswordAuth
-import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
-import org.matrix.android.sdk.internal.network.executeRequest
-import org.matrix.android.sdk.internal.task.Task
-import javax.inject.Inject
-
-internal interface DeleteDeviceWithUserPasswordTask : Task {
- data class Params(
- val deviceId: String,
- val authSession: String?,
- val password: String
- )
-}
-
-internal class DefaultDeleteDeviceWithUserPasswordTask @Inject constructor(
- private val cryptoApi: CryptoApi,
- @UserId private val userId: String,
- private val globalErrorReceiver: GlobalErrorReceiver
-) : DeleteDeviceWithUserPasswordTask {
-
- override suspend fun execute(params: DeleteDeviceWithUserPasswordTask.Params) {
- return executeRequest(globalErrorReceiver) {
- apiCall = cryptoApi.deleteDevice(params.deviceId,
- DeleteDeviceParams(
- auth = UserPasswordAuth(
- type = LoginFlowTypes.PASSWORD,
- session = params.authSession,
- user = userId,
- password = params.password
- ).asMap()
- )
- )
- }
- }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt
index ef31130f55..f8a8354e48 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt
@@ -126,11 +126,16 @@ internal class DefaultInitializeCrossSigningTask @Inject constructor(
uploadSigningKeysTask.execute(uploadSigningKeysParams)
} catch (failure: Throwable) {
if (params.interactiveAuthInterceptor == null
- || !handleUIA(failure, params.interactiveAuthInterceptor) { authUpdate ->
- uploadSigningKeysTask.execute(uploadSigningKeysParams.copy(userAuthParam = authUpdate))
- }) {
+ || !handleUIA(
+ failure = failure,
+ interceptor = params.interactiveAuthInterceptor,
+ retryBlock = { authUpdate ->
+ uploadSigningKeysTask.execute(uploadSigningKeysParams.copy(userAuthParam = authUpdate))
+ }
+ )
+ ) {
Timber.d("## UIA: propagate failure")
- throw failure
+ throw failure
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt
index d67b21567e..ca6b0554a9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt
@@ -16,10 +16,9 @@
package org.matrix.android.sdk.internal.session.account
+import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.internal.auth.registration.handleUIA
-import org.matrix.android.sdk.api.auth.UIABaseAuth
-import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.session.cleanup.CleanupSession
@@ -30,8 +29,8 @@ import javax.inject.Inject
internal interface DeactivateAccountTask : Task {
data class Params(
- val userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor,
val eraseAllData: Boolean,
+ val userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor,
val userAuthParam: UIABaseAuth? = null
)
}
@@ -39,7 +38,6 @@ internal interface DeactivateAccountTask : Task(globalErrorReceiver) {
apiCall = accountAPI.deactivate(deactivateAccountParams)
}
+ true
} catch (throwable: Throwable) {
- if (!handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth ->
- execute(params.copy(userAuthParam = auth))
- }
+ if (!handleUIA(
+ failure = throwable,
+ interceptor = params.userInteractiveAuthInterceptor,
+ retryBlock = { authUpdate ->
+ execute(params.copy(userAuthParam = authUpdate))
+ }
+ )
) {
Timber.d("## UIA: propagate failure")
- throw throwable
+ throw throwable
+ } else {
+ false
}
}
- // Logout from identity server if any, ignoring errors
- runCatching { identityDisconnectTask.execute(Unit) }
- .onFailure { Timber.w(it, "Unable to disconnect identity server") }
- cleanupSession.handle()
+ if (canCleanup) {
+ // Logout from identity server if any, ignoring errors
+ runCatching { identityDisconnectTask.execute(Unit) }
+ .onFailure { Timber.w(it, "Unable to disconnect identity server") }
+
+ cleanupSession.handle()
+ }
}
}
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 25b67159a9..dc77d7bffb 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
@@ -27,7 +27,7 @@ internal class DefaultAccountService @Inject constructor(private val changePassw
changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword))
}
- override suspend fun deactivateAccount(userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor, eraseAllData: Boolean) {
- deactivateAccountTask.execute(DeactivateAccountTask.Params(userInteractiveAuthInterceptor, eraseAllData))
+ override suspend fun deactivateAccount(eraseAllData: Boolean, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) {
+ deactivateAccountTask.execute(DeactivateAccountTask.Params(eraseAllData, userInteractiveAuthInterceptor))
}
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt
index 10690c59de..7d046cb642 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt
@@ -16,16 +16,12 @@
package org.matrix.android.sdk.internal.session.call
-import kotlinx.coroutines.Dispatchers
-import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.call.CallListener
import org.matrix.android.sdk.api.session.call.CallSignalingService
import org.matrix.android.sdk.api.session.call.MxCall
+import org.matrix.android.sdk.api.session.call.PSTNProtocolChecker
import org.matrix.android.sdk.api.session.call.TurnServerResponse
-import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.task.TaskExecutor
-import org.matrix.android.sdk.internal.task.launchToCallback
import timber.log.Timber
import javax.inject.Inject
@@ -34,14 +30,16 @@ internal class DefaultCallSignalingService @Inject constructor(
private val callSignalingHandler: CallSignalingHandler,
private val mxCallFactory: MxCallFactory,
private val activeCallHandler: ActiveCallHandler,
- private val taskExecutor: TaskExecutor,
- private val turnServerDataSource: TurnServerDataSource
+ private val turnServerDataSource: TurnServerDataSource,
+ private val pstnProtocolChecker: PSTNProtocolChecker
) : CallSignalingService {
- override fun getTurnServer(callback: MatrixCallback): Cancelable {
- return taskExecutor.executorScope.launchToCallback(Dispatchers.Default, callback) {
- turnServerDataSource.getTurnServer()
- }
+ override suspend fun getTurnServer(): TurnServerResponse {
+ return turnServerDataSource.getTurnServer()
+ }
+
+ override fun getPSTNProtocolChecker(): PSTNProtocolChecker {
+ return pstnProtocolChecker
}
override fun createOutgoingCall(roomId: String, otherUserId: String, isVideoCall: Boolean): MxCall {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt
index 916a602936..c2a38af093 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt
@@ -26,7 +26,6 @@ import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields
import org.matrix.android.sdk.internal.di.SessionDatabase
-import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.task.Task
@@ -47,11 +46,12 @@ internal class DefaultFinalizeAddingThreePidTask @Inject constructor(
private val profileAPI: ProfileAPI,
@SessionDatabase private val monarchy: Monarchy,
private val pendingThreePidMapper: PendingThreePidMapper,
- @UserId private val userId: String,
private val globalErrorReceiver: GlobalErrorReceiver) : FinalizeAddingThreePidTask() {
override suspend fun execute(params: Params) {
- if (params.userWantsToCancel.not()) {
+ val canCleanup = if (params.userWantsToCancel) {
+ true
+ } else {
// Get the required pending data
val pendingThreePids = monarchy.fetchAllMappedSync(
{ it.where(PendingThreePidEntity::class.java) },
@@ -69,21 +69,30 @@ internal class DefaultFinalizeAddingThreePidTask @Inject constructor(
)
apiCall = profileAPI.finalizeAddThreePid(body)
}
+ true
} catch (throwable: Throwable) {
if (params.userInteractiveAuthInterceptor == null
- || !handleUIA(throwable, params.userInteractiveAuthInterceptor) { auth ->
- execute(params.copy(userAuthParam = auth))
- }
+ || !handleUIA(
+ failure = throwable,
+ interceptor = params.userInteractiveAuthInterceptor,
+ retryBlock = { authUpdate ->
+ execute(params.copy(userAuthParam = authUpdate))
+ }
+ )
) {
Timber.d("## UIA: propagate failure")
- throw throwable.toRegistrationFlowResponse()
+ throw throwable.toRegistrationFlowResponse()
?.let { Failure.RegistrationFlowError(it) }
?: throwable
+ } else {
+ false
}
}
}
- cleanupDatabase(params)
+ if (canCleanup) {
+ cleanupDatabase(params)
+ }
}
private suspend fun cleanupDatabase(params: Params) {
diff --git a/tools/release/download_buildkite_artifacts.py b/tools/release/download_buildkite_artifacts.py
index 067a1a4dfe..cd1abecfa5 100755
--- a/tools/release/download_buildkite_artifacts.py
+++ b/tools/release/download_buildkite_artifacts.py
@@ -41,6 +41,9 @@ parser.add_argument('-b',
type=int,
required=True,
help='the buildkite build number.')
+parser.add_argument('-f',
+ '--filename',
+ help='the filename, to download only one artifact.')
parser.add_argument('-e',
'--expecting',
type=int,
@@ -148,6 +151,8 @@ for elt in data:
print(" %s: %s" % (key, str(value)))
url = elt.get("download_url")
filename = elt.get("filename")
+ if args.filename is not None and args.filename != filename:
+ continue
target = targetDir + "/" + filename
print("Downloading %s to '%s'..." % (filename, targetDir))
if not args.simulate:
diff --git a/vector/src/main/java/im/vector/app/core/epoxy/TimelineEmptyItem.kt b/vector/src/main/java/im/vector/app/core/epoxy/TimelineEmptyItem.kt
new file mode 100644
index 0000000000..b77670ba76
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/core/epoxy/TimelineEmptyItem.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.core.epoxy
+
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.app.R
+import im.vector.app.features.home.room.detail.timeline.item.ItemWithEvents
+
+@EpoxyModelClass(layout = R.layout.item_timeline_empty)
+abstract class TimelineEmptyItem : VectorEpoxyModel(), ItemWithEvents {
+
+ @EpoxyAttribute lateinit var eventId: String
+
+ override fun getEventIds(): List {
+ return listOf(eventId)
+ }
+
+ class Holder : VectorEpoxyHolder()
+}
diff --git a/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt b/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt
index 0385973386..ce23111a95 100644
--- a/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt
@@ -113,7 +113,7 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory {
override fun onResume() {
super.onResume()
- // It's the only way we have to know if sso falback flow was successful
+ // It's the only way we have to know if sso fallback flow was successful
withState(sharedViewModel) {
if (it.ssoFallbackPageWasShown) {
Timber.d("## UIA ssoFallbackPageWasShown tentative success")
diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt
index 25b2a80a85..8a2d56a5a2 100644
--- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt
@@ -16,6 +16,7 @@
package im.vector.app.features.call
+import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MvRxViewModelFactory
@@ -29,17 +30,16 @@ import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.call.audio.CallAudioManager
import im.vector.app.features.call.webrtc.WebRtcCall
import im.vector.app.features.call.webrtc.WebRtcCallManager
-import org.matrix.android.sdk.api.MatrixCallback
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.call.CallState
import org.matrix.android.sdk.api.session.call.MxCall
import org.matrix.android.sdk.api.session.call.MxPeerConnectionState
-import org.matrix.android.sdk.api.session.call.TurnServerResponse
import org.matrix.android.sdk.api.session.room.model.call.supportCallTransfer
import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.api.util.toMatrixItem
-import java.util.Timer
-import java.util.TimerTask
class VectorCallViewModel @AssistedInject constructor(
@Assisted initialState: VectorCallViewState,
@@ -50,7 +50,7 @@ class VectorCallViewModel @AssistedInject constructor(
private var call: WebRtcCall? = null
- private var connectionTimeoutTimer: Timer? = null
+ private var connectionTimeoutJob: Job? = null
private var hasBeenConnectedOnce = false
private val callListener = object : WebRtcCall.Listener {
@@ -92,26 +92,20 @@ class VectorCallViewModel @AssistedInject constructor(
val callState = call.state
if (callState is CallState.Connected && callState.iceConnectionState == MxPeerConnectionState.CONNECTED) {
hasBeenConnectedOnce = true
- connectionTimeoutTimer?.cancel()
- connectionTimeoutTimer = null
+ connectionTimeoutJob?.cancel()
+ connectionTimeoutJob = null
} else {
// do we reset as long as it's moving?
- connectionTimeoutTimer?.cancel()
+ connectionTimeoutJob?.cancel()
if (hasBeenConnectedOnce) {
- connectionTimeoutTimer = Timer().apply {
- schedule(object : TimerTask() {
- override fun run() {
- session.callSignalingService().getTurnServer(object : MatrixCallback {
- override fun onFailure(failure: Throwable) {
- _viewEvents.post(VectorCallViewEvents.ConnectionTimeout(null))
- }
-
- override fun onSuccess(data: TurnServerResponse) {
- _viewEvents.post(VectorCallViewEvents.ConnectionTimeout(data))
- }
- })
- }
- }, 30_000)
+ connectionTimeoutJob = viewModelScope.launch {
+ delay(30_000)
+ try {
+ val turn = session.callSignalingService().getTurnServer()
+ _viewEvents.post(VectorCallViewEvents.ConnectionTimeout(turn))
+ } catch (failure: Throwable) {
+ _viewEvents.post(VectorCallViewEvents.ConnectionTimeout(null))
+ }
}
}
}
diff --git a/vector/src/main/java/im/vector/app/features/call/audio/CallAudioManager.kt b/vector/src/main/java/im/vector/app/features/call/audio/CallAudioManager.kt
index 66370763e1..36a11b5923 100644
--- a/vector/src/main/java/im/vector/app/features/call/audio/CallAudioManager.kt
+++ b/vector/src/main/java/im/vector/app/features/call/audio/CallAudioManager.kt
@@ -83,12 +83,12 @@ class CallAudioManager(private val context: Context, val configChange: (() -> Un
fun setAudioDevice(device: Device) {
runInAudioThread(Runnable {
if (!_availableDevices.contains(device)) {
- Timber.w(" Audio device not available: $device")
+ Timber.w("Audio device not available: $device")
userSelectedDevice = null
return@Runnable
}
if (mode != Mode.DEFAULT) {
- Timber.i(" User selected device set to: $device")
+ Timber.i("User selected device set to: $device")
userSelectedDevice = device
updateAudioRoute(mode, false)
}
@@ -108,7 +108,7 @@ class CallAudioManager(private val context: Context, val configChange: (() -> Un
success = updateAudioRoute(mode, false)
} catch (e: Throwable) {
success = false
- Timber.e(e, " Failed to update audio route for mode: " + mode)
+ Timber.e(e, "Failed to update audio route for mode: $mode")
}
if (success) {
this@CallAudioManager.mode = mode
@@ -124,7 +124,7 @@ class CallAudioManager(private val context: Context, val configChange: (() -> Un
* `false`, otherwise.
*/
private fun updateAudioRoute(mode: Mode, force: Boolean): Boolean {
- Timber.i(" Update audio route for mode: " + mode)
+ Timber.i("Update audio route for mode: $mode")
if (!audioDeviceRouter?.setMode(mode).orFalse()) {
return false
}
@@ -158,7 +158,7 @@ class CallAudioManager(private val context: Context, val configChange: (() -> Un
return true
}
selectedDevice = audioDevice
- Timber.i(" Selected audio device: " + audioDevice)
+ Timber.i("Selected audio device: $audioDevice")
audioDeviceRouter?.setAudioRoute(audioDevice)
configChange?.invoke()
return true
diff --git a/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadLookup.kt b/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadLookup.kt
index 1c5caee2cd..6fccea6c8c 100644
--- a/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadLookup.kt
+++ b/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadLookup.kt
@@ -22,20 +22,22 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.Session
import javax.inject.Inject
-class DialPadLookup @Inject constructor(val session: Session,
- val directRoomHelper: DirectRoomHelper,
- val callManager: WebRtcCallManager
+class DialPadLookup @Inject constructor(
+ private val session: Session,
+ private val directRoomHelper: DirectRoomHelper,
+ private val callManager: WebRtcCallManager
) {
-
class Failure : Throwable()
+
data class Result(val userId: String, val roomId: String)
suspend fun lookupPhoneNumber(phoneNumber: String): Result {
val supportedProtocolKey = callManager.supportedPSTNProtocol ?: throw Failure()
val thirdPartyUser = tryOrNull {
- session.thirdPartyService().getThirdPartyUser(supportedProtocolKey, fields = mapOf(
- "m.id.phone" to phoneNumber
- )).firstOrNull()
+ session.thirdPartyService().getThirdPartyUser(
+ protocol = supportedProtocolKey,
+ fields = mapOf("m.id.phone" to phoneNumber)
+ ).firstOrNull()
} ?: throw Failure()
val roomId = directRoomHelper.ensureDMExists(thirdPartyUser.userId)
diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/PSTNProtocol.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/PSTNProtocol.kt
deleted file mode 100644
index 3e6d2df690..0000000000
--- a/vector/src/main/java/im/vector/app/features/call/webrtc/PSTNProtocol.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2021 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.vector.app.features.call.webrtc
-
-import kotlinx.coroutines.delay
-import org.matrix.android.sdk.api.session.Session
-import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol
-
-private const val PSTN_VECTOR_KEY = "im.vector.protocol.pstn"
-private const val PSTN_MATRIX_KEY = "m.protocol.pstn"
-
-suspend fun Session.getSupportedPSTN(maxTries: Int): String? {
- val thirdPartyProtocols: Map = try {
- thirdPartyService().getThirdPartyProtocols()
- } catch (failure: Throwable) {
- if (maxTries == 1) {
- return null
- } else {
- // Wait for 10s before trying again
- delay(10_000L)
- return getSupportedPSTN(maxTries - 1)
- }
- }
- return when {
- thirdPartyProtocols.containsKey(PSTN_VECTOR_KEY) -> PSTN_VECTOR_KEY
- thirdPartyProtocols.containsKey(PSTN_MATRIX_KEY) -> PSTN_MATRIX_KEY
- else -> null
- }
-}
diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt
index c72d7c8a76..469fba4d5e 100644
--- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt
+++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt
@@ -53,7 +53,6 @@ import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
import org.matrix.android.sdk.api.session.room.model.call.CallNegotiateContent
import org.matrix.android.sdk.api.session.room.model.call.SdpType
-import org.matrix.android.sdk.internal.util.awaitCallback
import org.threeten.bp.Duration
import org.webrtc.AudioSource
import org.webrtc.AudioTrack
@@ -420,9 +419,7 @@ class WebRtcCall(val mxCall: MxCall,
private suspend fun getTurnServer(): TurnServerResponse? {
return tryOrNull {
- awaitCallback {
- sessionProvider.get()?.callSignalingService()?.getTurnServer(it)
- }
+ sessionProvider.get()?.callSignalingService()?.getTurnServer()
}
}
diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt
index 95728e0a97..2f8f84051e 100644
--- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt
+++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt
@@ -26,14 +26,13 @@ import im.vector.app.features.call.VectorCallActivity
import im.vector.app.features.call.audio.CallAudioManager
import im.vector.app.features.call.utils.EglUtils
import im.vector.app.push.fcm.FcmHelper
-import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.asCoroutineDispatcher
-import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.call.CallListener
import org.matrix.android.sdk.api.session.call.CallState
import org.matrix.android.sdk.api.session.call.MxCall
+import org.matrix.android.sdk.api.session.call.PSTNProtocolChecker
import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent
import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent
import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent
@@ -65,22 +64,26 @@ class WebRtcCallManager @Inject constructor(
private val currentSession: Session?
get() = activeSessionDataSource.currentValue?.orNull()
+ private val pstnProtocolChecker: PSTNProtocolChecker?
+ get() = currentSession?.callSignalingService()?.getPSTNProtocolChecker()
+
interface CurrentCallListener {
fun onCurrentCallChange(call: WebRtcCall?) {}
fun onAudioDevicesChange() {}
}
- interface PSTNSupportListener {
- fun onPSTNSupportUpdated()
+ val supportedPSTNProtocol: String?
+ get() = pstnProtocolChecker?.supportedPSTNProtocol
+
+ val supportsPSTNProtocol: Boolean
+ get() = supportedPSTNProtocol != null
+
+ fun addPstnSupportListener(listener: PSTNProtocolChecker.Listener) {
+ pstnProtocolChecker?.addListener(listener)
}
- private val pstnSupportListeners = emptyList().toMutableList()
- fun addPstnSupportListener(listener: PSTNSupportListener) {
- pstnSupportListeners.add(listener)
- }
-
- fun removePstnSupportListener(listener: PSTNSupportListener) {
- pstnSupportListeners.remove(listener)
+ fun removePstnSupportListener(listener: PSTNProtocolChecker.Listener) {
+ pstnProtocolChecker?.removeListener(listener)
}
private val currentCallsListeners = CopyOnWriteArrayList()
@@ -104,27 +107,11 @@ class WebRtcCallManager @Inject constructor(
private var peerConnectionFactory: PeerConnectionFactory? = null
private val executor = Executors.newSingleThreadExecutor()
private val dispatcher = executor.asCoroutineDispatcher()
- var supportedPSTNProtocol: String? = null
- private set
-
- val supportsPSTNProtocol: Boolean
- get() = supportedPSTNProtocol != null
private val rootEglBase by lazy { EglUtils.rootEglBase }
private var isInBackground: Boolean = true
- init {
- GlobalScope.launch {
- supportedPSTNProtocol = currentSession?.getSupportedPSTN(3)
- if (supportedPSTNProtocol != null) {
- pstnSupportListeners.forEach {
- tryOrNull { it.onPSTNSupportUpdated() }
- }
- }
- }
- }
-
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun entersForeground() {
isInBackground = false
@@ -167,6 +154,10 @@ class WebRtcCallManager @Inject constructor(
return callsByCallId.values.toList()
}
+ fun checkForPSTNSupportIfNeeded() {
+ pstnProtocolChecker?.checkForPSTNSupportIfNeeded()
+ }
+
/**
* @return a set of all advertised call during the lifetime of the app.
*/
@@ -176,7 +167,6 @@ class WebRtcCallManager @Inject constructor(
Timber.v("## VOIP headSetButtonTapped")
val call = getCurrentCall() ?: return
if (call.mxCall.state is CallState.LocalRinging) {
- // accept call
call.acceptIncomingCall()
}
if (call.mxCall.state is CallState.Connected) {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt
index 42278cd948..fe55d81cc4 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt
@@ -55,6 +55,7 @@ import org.matrix.android.sdk.internal.util.awaitCallback
import java.io.OutputStream
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
class BootstrapSharedViewModel @AssistedInject constructor(
@Assisted initialState: BootstrapViewState,
@@ -421,7 +422,7 @@ class BootstrapSharedViewModel @AssistedInject constructor(
_viewEvents.post(BootstrapViewEvents.RequestReAuth(flowResponse, errCode))
}
else -> {
- promise.resumeWith(Result.failure(UnsupportedOperationException()))
+ promise.resumeWithException(UnsupportedOperationException())
}
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
index 44e02fea0b..62bdc61b63 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
@@ -52,6 +52,7 @@ import org.matrix.android.sdk.rx.rx
import timber.log.Timber
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
class HomeActivityViewModel @AssistedInject constructor(
@Assisted initialState: HomeActivityViewState,
@@ -228,7 +229,7 @@ class HomeActivityViewModel @AssistedInject constructor(
)
)
} else {
- promise.resumeWith(Result.failure(Exception("Cannot silently initialize cross signing, UIA missing")))
+ promise.resumeWithException(Exception("Cannot silently initialize cross signing, UIA missing"))
}
}
},
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
index 331be9d825..c7a5873a65 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
@@ -26,8 +26,8 @@ import com.airbnb.mvrx.ViewModelContext
import com.jakewharton.rxrelay2.BehaviorRelay
import com.jakewharton.rxrelay2.PublishRelay
import dagger.assisted.Assisted
-import dagger.assisted.AssistedInject
import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
import im.vector.app.R
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel
@@ -64,6 +64,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.raw.RawService
import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.call.PSTNProtocolChecker
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.LocalEcho
@@ -120,7 +121,7 @@ class RoomDetailViewModel @AssistedInject constructor(
private val directRoomHelper: DirectRoomHelper,
timelineSettingsFactory: TimelineSettingsFactory
) : VectorViewModel(initialState),
- Timeline.Listener, ChatEffectManager.Delegate, WebRtcCallManager.PSTNSupportListener {
+ Timeline.Listener, ChatEffectManager.Delegate, PSTNProtocolChecker.Listener {
private val room = session.getRoom(initialState.roomId)!!
private val eventId = initialState.eventId
@@ -176,6 +177,7 @@ class RoomDetailViewModel @AssistedInject constructor(
// Inform the SDK that the room is displayed
session.onRoomDisplayed(initialState.roomId)
callManager.addPstnSupportListener(this)
+ callManager.checkForPSTNSupportIfNeeded()
chatEffectManager.delegate = this
}
@@ -231,65 +233,65 @@ class RoomDetailViewModel @AssistedInject constructor(
override fun handle(action: RoomDetailAction) {
when (action) {
- is RoomDetailAction.UserIsTyping -> handleUserIsTyping(action)
- is RoomDetailAction.SaveDraft -> handleSaveDraft(action)
- is RoomDetailAction.SendMessage -> handleSendMessage(action)
- is RoomDetailAction.SendMedia -> handleSendMedia(action)
- is RoomDetailAction.SendSticker -> handleSendSticker(action)
- is RoomDetailAction.TimelineEventTurnsVisible -> handleEventVisible(action)
- is RoomDetailAction.TimelineEventTurnsInvisible -> handleEventInvisible(action)
- is RoomDetailAction.LoadMoreTimelineEvents -> handleLoadMore(action)
- is RoomDetailAction.SendReaction -> handleSendReaction(action)
- is RoomDetailAction.AcceptInvite -> handleAcceptInvite()
- is RoomDetailAction.RejectInvite -> handleRejectInvite()
- is RoomDetailAction.RedactAction -> handleRedactEvent(action)
- is RoomDetailAction.UndoReaction -> handleUndoReact(action)
- is RoomDetailAction.UpdateQuickReactAction -> handleUpdateQuickReaction(action)
- is RoomDetailAction.EnterRegularMode -> handleEnterRegularMode(action)
- is RoomDetailAction.EnterEditMode -> handleEditAction(action)
- is RoomDetailAction.EnterQuoteMode -> handleQuoteAction(action)
- is RoomDetailAction.EnterReplyMode -> handleReplyAction(action)
- is RoomDetailAction.DownloadOrOpen -> handleOpenOrDownloadFile(action)
- is RoomDetailAction.NavigateToEvent -> handleNavigateToEvent(action)
- is RoomDetailAction.HandleTombstoneEvent -> handleTombstoneEvent(action)
- is RoomDetailAction.ResendMessage -> handleResendEvent(action)
- is RoomDetailAction.RemoveFailedEcho -> handleRemove(action)
- is RoomDetailAction.ResendAll -> handleResendAll()
- is RoomDetailAction.MarkAllAsRead -> handleMarkAllAsRead()
- is RoomDetailAction.ReportContent -> handleReportContent(action)
- is RoomDetailAction.IgnoreUser -> handleIgnoreUser(action)
+ is RoomDetailAction.UserIsTyping -> handleUserIsTyping(action)
+ is RoomDetailAction.SaveDraft -> handleSaveDraft(action)
+ is RoomDetailAction.SendMessage -> handleSendMessage(action)
+ is RoomDetailAction.SendMedia -> handleSendMedia(action)
+ is RoomDetailAction.SendSticker -> handleSendSticker(action)
+ is RoomDetailAction.TimelineEventTurnsVisible -> handleEventVisible(action)
+ is RoomDetailAction.TimelineEventTurnsInvisible -> handleEventInvisible(action)
+ is RoomDetailAction.LoadMoreTimelineEvents -> handleLoadMore(action)
+ is RoomDetailAction.SendReaction -> handleSendReaction(action)
+ is RoomDetailAction.AcceptInvite -> handleAcceptInvite()
+ is RoomDetailAction.RejectInvite -> handleRejectInvite()
+ is RoomDetailAction.RedactAction -> handleRedactEvent(action)
+ is RoomDetailAction.UndoReaction -> handleUndoReact(action)
+ is RoomDetailAction.UpdateQuickReactAction -> handleUpdateQuickReaction(action)
+ is RoomDetailAction.EnterRegularMode -> handleEnterRegularMode(action)
+ is RoomDetailAction.EnterEditMode -> handleEditAction(action)
+ is RoomDetailAction.EnterQuoteMode -> handleQuoteAction(action)
+ is RoomDetailAction.EnterReplyMode -> handleReplyAction(action)
+ is RoomDetailAction.DownloadOrOpen -> handleOpenOrDownloadFile(action)
+ is RoomDetailAction.NavigateToEvent -> handleNavigateToEvent(action)
+ is RoomDetailAction.HandleTombstoneEvent -> handleTombstoneEvent(action)
+ is RoomDetailAction.ResendMessage -> handleResendEvent(action)
+ is RoomDetailAction.RemoveFailedEcho -> handleRemove(action)
+ is RoomDetailAction.ResendAll -> handleResendAll()
+ is RoomDetailAction.MarkAllAsRead -> handleMarkAllAsRead()
+ is RoomDetailAction.ReportContent -> handleReportContent(action)
+ is RoomDetailAction.IgnoreUser -> handleIgnoreUser(action)
is RoomDetailAction.EnterTrackingUnreadMessagesState -> startTrackingUnreadMessages()
- is RoomDetailAction.ExitTrackingUnreadMessagesState -> stopTrackingUnreadMessages()
- is RoomDetailAction.ReplyToOptions -> handleReplyToOptions(action)
- is RoomDetailAction.AcceptVerificationRequest -> handleAcceptVerification(action)
- is RoomDetailAction.DeclineVerificationRequest -> handleDeclineVerification(action)
- is RoomDetailAction.RequestVerification -> handleRequestVerification(action)
- is RoomDetailAction.ResumeVerification -> handleResumeRequestVerification(action)
- is RoomDetailAction.ReRequestKeys -> handleReRequestKeys(action)
- is RoomDetailAction.TapOnFailedToDecrypt -> handleTapOnFailedToDecrypt(action)
- is RoomDetailAction.SelectStickerAttachment -> handleSelectStickerAttachment()
- is RoomDetailAction.OpenIntegrationManager -> handleOpenIntegrationManager()
- is RoomDetailAction.StartCallWithPhoneNumber -> handleStartCallWithPhoneNumber(action)
- is RoomDetailAction.StartCall -> handleStartCall(action)
- is RoomDetailAction.AcceptCall -> handleAcceptCall(action)
- is RoomDetailAction.EndCall -> handleEndCall()
- is RoomDetailAction.ManageIntegrations -> handleManageIntegrations()
- is RoomDetailAction.AddJitsiWidget -> handleAddJitsiConference(action)
- is RoomDetailAction.RemoveWidget -> handleDeleteWidget(action.widgetId)
- is RoomDetailAction.EnsureNativeWidgetAllowed -> handleCheckWidgetAllowed(action)
- is RoomDetailAction.CancelSend -> handleCancel(action)
- is RoomDetailAction.OpenOrCreateDm -> handleOpenOrCreateDm(action)
- is RoomDetailAction.JumpToReadReceipt -> handleJumpToReadReceipt(action)
- RoomDetailAction.QuickActionInvitePeople -> handleInvitePeople()
- RoomDetailAction.QuickActionSetAvatar -> handleQuickSetAvatar()
- is RoomDetailAction.SetAvatarAction -> handleSetNewAvatar(action)
- RoomDetailAction.QuickActionSetTopic -> _viewEvents.post(RoomDetailViewEvents.OpenRoomSettings)
- is RoomDetailAction.ShowRoomAvatarFullScreen -> {
+ is RoomDetailAction.ExitTrackingUnreadMessagesState -> stopTrackingUnreadMessages()
+ is RoomDetailAction.ReplyToOptions -> handleReplyToOptions(action)
+ is RoomDetailAction.AcceptVerificationRequest -> handleAcceptVerification(action)
+ is RoomDetailAction.DeclineVerificationRequest -> handleDeclineVerification(action)
+ is RoomDetailAction.RequestVerification -> handleRequestVerification(action)
+ is RoomDetailAction.ResumeVerification -> handleResumeRequestVerification(action)
+ is RoomDetailAction.ReRequestKeys -> handleReRequestKeys(action)
+ is RoomDetailAction.TapOnFailedToDecrypt -> handleTapOnFailedToDecrypt(action)
+ is RoomDetailAction.SelectStickerAttachment -> handleSelectStickerAttachment()
+ is RoomDetailAction.OpenIntegrationManager -> handleOpenIntegrationManager()
+ is RoomDetailAction.StartCallWithPhoneNumber -> handleStartCallWithPhoneNumber(action)
+ is RoomDetailAction.StartCall -> handleStartCall(action)
+ is RoomDetailAction.AcceptCall -> handleAcceptCall(action)
+ is RoomDetailAction.EndCall -> handleEndCall()
+ is RoomDetailAction.ManageIntegrations -> handleManageIntegrations()
+ is RoomDetailAction.AddJitsiWidget -> handleAddJitsiConference(action)
+ is RoomDetailAction.RemoveWidget -> handleDeleteWidget(action.widgetId)
+ is RoomDetailAction.EnsureNativeWidgetAllowed -> handleCheckWidgetAllowed(action)
+ is RoomDetailAction.CancelSend -> handleCancel(action)
+ is RoomDetailAction.OpenOrCreateDm -> handleOpenOrCreateDm(action)
+ is RoomDetailAction.JumpToReadReceipt -> handleJumpToReadReceipt(action)
+ RoomDetailAction.QuickActionInvitePeople -> handleInvitePeople()
+ RoomDetailAction.QuickActionSetAvatar -> handleQuickSetAvatar()
+ is RoomDetailAction.SetAvatarAction -> handleSetNewAvatar(action)
+ RoomDetailAction.QuickActionSetTopic -> _viewEvents.post(RoomDetailViewEvents.OpenRoomSettings)
+ is RoomDetailAction.ShowRoomAvatarFullScreen -> {
_viewEvents.post(
RoomDetailViewEvents.ShowRoomAvatarFullScreen(action.matrixItem, action.transitionView)
)
}
- is RoomDetailAction.DoNotShowPreviewUrlFor -> handleDoNotShowPreviewUrlFor(action)
+ is RoomDetailAction.DoNotShowPreviewUrlFor -> handleDoNotShowPreviewUrlFor(action)
}.exhaustive
}
@@ -618,10 +620,10 @@ class RoomDetailViewModel @AssistedInject constructor(
return@withState false
}
when (itemId) {
- R.id.resend_all -> state.asyncRoomSummary()?.hasFailedSending == true
+ R.id.resend_all -> state.asyncRoomSummary()?.hasFailedSending == true
R.id.timeline_setting -> true
- R.id.invite -> state.canInvite
- R.id.clear_all -> state.asyncRoomSummary()?.hasFailedSending == true
+ R.id.invite -> state.canInvite
+ R.id.clear_all -> state.asyncRoomSummary()?.hasFailedSending == true
R.id.open_matrix_apps -> true
R.id.voice_call,
R.id.video_call -> callManager.getCallsByRoomId(state.roomId).isEmpty()
@@ -741,7 +743,7 @@ class RoomDetailViewModel @AssistedInject constructor(
_viewEvents.post(RoomDetailViewEvents.SlashCommandHandled())
popDraft()
}
- is ParsedCommand.SendChatEffect -> {
+ is ParsedCommand.SendChatEffect -> {
sendChatEffect(slashCommandResult)
_viewEvents.post(RoomDetailViewEvents.SlashCommandHandled())
popDraft()
@@ -774,7 +776,7 @@ class RoomDetailViewModel @AssistedInject constructor(
}
}.exhaustive
}
- is SendMode.EDIT -> {
+ is SendMode.EDIT -> {
// is original event a reply?
val inReplyTo = state.sendMode.timelineEvent.getRelationContent()?.inReplyTo?.eventId
if (inReplyTo != null) {
@@ -799,7 +801,7 @@ class RoomDetailViewModel @AssistedInject constructor(
_viewEvents.post(RoomDetailViewEvents.MessageSent)
popDraft()
}
- is SendMode.QUOTE -> {
+ is SendMode.QUOTE -> {
val messageContent: MessageContent? =
state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel()
?: state.sendMode.timelineEvent.root.getClearContent().toModel()
@@ -822,7 +824,7 @@ class RoomDetailViewModel @AssistedInject constructor(
_viewEvents.post(RoomDetailViewEvents.MessageSent)
popDraft()
}
- is SendMode.REPLY -> {
+ is SendMode.REPLY -> {
state.sendMode.timelineEvent.let {
room.replyToMessage(it, action.text.toString(), action.autoMarkdown)
_viewEvents.post(RoomDetailViewEvents.MessageSent)
@@ -1441,7 +1443,7 @@ class RoomDetailViewModel @AssistedInject constructor(
}
override fun onPSTNSupportUpdated() {
- updateShowDialerOptionState()
+ updateShowDialerOptionState()
}
private fun updateShowDialerOptionState() {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/ScrollOnNewMessageCallback.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/ScrollOnNewMessageCallback.kt
index af56e2eb02..fbf9ebe32f 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/ScrollOnNewMessageCallback.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/ScrollOnNewMessageCallback.kt
@@ -19,7 +19,7 @@ package im.vector.app.features.home.room.detail
import androidx.recyclerview.widget.LinearLayoutManager
import im.vector.app.core.platform.DefaultListUpdateCallback
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
-import im.vector.app.features.home.room.detail.timeline.item.BaseEventItem
+import im.vector.app.features.home.room.detail.timeline.item.ItemWithEvents
import timber.log.Timber
import java.util.concurrent.CopyOnWriteArrayList
@@ -47,8 +47,8 @@ class ScrollOnNewMessageCallback(private val layoutManager: LinearLayoutManager,
if (layoutManager.findFirstVisibleItemPosition() != position) {
return
}
- val firstNewItem = timelineEventController.adapter.getModelAtPosition(position) as? BaseEventItem ?: return
- val firstNewItemIds = firstNewItem.getEventIds().firstOrNull()
+ val firstNewItem = timelineEventController.adapter.getModelAtPosition(position) as? ItemWithEvents ?: return
+ val firstNewItemIds = firstNewItem.getEventIds().firstOrNull() ?: return
val indexOfFirstNewItem = newTimelineEventIds.indexOf(firstNewItemIds)
if (indexOfFirstNewItem != -1) {
Timber.v("Should scroll to position: $position")
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt
index 29871cf307..9acd34c827 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt
@@ -38,18 +38,15 @@ import im.vector.app.features.home.room.detail.timeline.factory.MergedHeaderItem
import im.vector.app.features.home.room.detail.timeline.factory.TimelineItemFactory
import im.vector.app.features.home.room.detail.timeline.helper.ContentDownloadStateTrackerBinder
import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
-import im.vector.app.features.home.room.detail.timeline.helper.ReadMarkerVisibilityStateChangedListener
+import im.vector.app.features.home.room.detail.timeline.helper.TimelineControllerInterceptorHelper
import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventDiffUtilCallback
import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventVisibilityStateChangedListener
import im.vector.app.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
-import im.vector.app.features.home.room.detail.timeline.item.BaseEventItem
import im.vector.app.features.home.room.detail.timeline.item.BasedMergedItem
-import im.vector.app.features.home.room.detail.timeline.item.CallTileTimelineItem
import im.vector.app.features.home.room.detail.timeline.item.DaySeparatorItem
import im.vector.app.features.home.room.detail.timeline.item.DaySeparatorItem_
import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData
-import im.vector.app.features.home.room.detail.timeline.item.TimelineReadMarkerItem_
import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever
import im.vector.app.features.media.ImageContentRenderer
import im.vector.app.features.media.VideoContentRenderer
@@ -194,75 +191,20 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
}
}
+ private val interceptorHelper = TimelineControllerInterceptorHelper(
+ ::positionOfReadMarker,
+ adapterPositionMapping,
+ vectorPreferences,
+ callManager
+ )
+
init {
addInterceptor(this)
requestModelBuild()
}
- // Update position when we are building new items
override fun intercept(models: MutableList>) = synchronized(modelCache) {
- positionOfReadMarker = null
- adapterPositionMapping.clear()
- val callIds = mutableSetOf()
- val modelsIterator = models.listIterator()
- val showHiddenEvents = vectorPreferences.shouldShowHiddenEvents()
- modelsIterator.withIndex().forEach {
- val index = it.index
- val epoxyModel = it.value
- if (epoxyModel is CallTileTimelineItem) {
- val callId = epoxyModel.attributes.callId
- // We should remove the call tile if we already have one for this call or
- // if this is an active call tile without an actual call (which can happen with permalink)
- val shouldRemoveCallItem = callIds.contains(callId)
- || (!callManager.getAdvertisedCalls().contains(callId) && epoxyModel.attributes.callStatus.isActive())
- if (shouldRemoveCallItem && !showHiddenEvents) {
- modelsIterator.remove()
- return@forEach
- }
- callIds.add(callId)
- }
- if (epoxyModel is BaseEventItem) {
- epoxyModel.getEventIds().forEach { eventId ->
- adapterPositionMapping[eventId] = index
- }
- }
- }
- val currentUnreadState = this.unreadState
- if (currentUnreadState is UnreadState.HasUnread) {
- val position = adapterPositionMapping[currentUnreadState.firstUnreadEventId]?.plus(1)
- positionOfReadMarker = position
- if (position != null) {
- val readMarker = TimelineReadMarkerItem_()
- .also {
- it.id("read_marker")
- it.setOnVisibilityStateChanged(ReadMarkerVisibilityStateChangedListener(callback))
- }
- models.add(position, readMarker)
- }
- }
- val shouldAddBackwardPrefetch = timeline?.hasMoreToLoad(Timeline.Direction.BACKWARDS) ?: false
- if (shouldAddBackwardPrefetch) {
- val indexOfPrefetchBackward = (previousModelsSize - 1)
- .coerceAtMost(models.size - DEFAULT_PREFETCH_THRESHOLD)
- .coerceAtLeast(0)
-
- val loadingItem = LoadingItem_()
- .id("prefetch_backward_loading${System.currentTimeMillis()}")
- .showLoader(false)
- .setVisibilityStateChangedListener(Timeline.Direction.BACKWARDS)
-
- models.add(indexOfPrefetchBackward, loadingItem)
- }
- val shouldAddForwardPrefetch = timeline?.hasMoreToLoad(Timeline.Direction.FORWARDS) ?: false
- if (shouldAddForwardPrefetch) {
- val indexOfPrefetchForward = DEFAULT_PREFETCH_THRESHOLD.coerceAtMost(models.size - 1)
- val loadingItem = LoadingItem_()
- .id("prefetch_forward_loading${System.currentTimeMillis()}")
- .showLoader(false)
- .setVisibilityStateChangedListener(Timeline.Direction.FORWARDS)
- models.add(indexOfPrefetchForward, loadingItem)
- }
- previousModelsSize = models.size
+ interceptorHelper.intercept(models, unreadState, timeline, callback)
}
fun update(viewState: RoomDetailViewState) {
@@ -431,6 +373,14 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
}
}
+ private fun LoadingItem_.setVisibilityStateChangedListener(direction: Timeline.Direction): LoadingItem_ {
+ return onVisibilityStateChanged { _, _, visibilityState ->
+ if (visibilityState == VisibilityState.VISIBLE) {
+ callback?.onLoadMore(direction)
+ }
+ }
+ }
+
private fun updateUTDStates(event: TimelineEvent, nextEvent: TimelineEvent?) {
if (vectorPreferences.labShowCompleteHistoryInEncryptedRoom()) {
return
@@ -461,14 +411,6 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
return shouldAdd
}
- private fun LoadingItem_.setVisibilityStateChangedListener(direction: Timeline.Direction): LoadingItem_ {
- return onVisibilityStateChanged { _, _, visibilityState ->
- if (visibilityState == VisibilityState.VISIBLE) {
- callback?.onLoadMore(direction)
- }
- }
- }
-
fun searchPositionOfEvent(eventId: String?): Int? = synchronized(modelCache) {
return adapterPositionMapping[eventId]
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactory.kt
index 982ceb906c..7fd50147d4 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactory.kt
@@ -16,7 +16,8 @@
package im.vector.app.features.home.room.detail.timeline.factory
-import im.vector.app.core.epoxy.EmptyItem_
+import im.vector.app.core.epoxy.TimelineEmptyItem
+import im.vector.app.core.epoxy.TimelineEmptyItem_
import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.resources.UserPreferencesProvider
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
@@ -114,6 +115,12 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me
Timber.e(throwable, "failed to create message item")
defaultItemFactory.create(event, highlight, callback, throwable)
}
- return (computedModel ?: EmptyItem_())
+ return computedModel ?: buildEmptyItem(event)
+ }
+
+ private fun buildEmptyItem(timelineEvent: TimelineEvent): TimelineEmptyItem {
+ return TimelineEmptyItem_()
+ .id(timelineEvent.localId)
+ .eventId(timelineEvent.eventId)
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt
new file mode 100644
index 0000000000..971a3a35d8
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2021 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.home.room.detail.timeline.helper
+
+import com.airbnb.epoxy.EpoxyModel
+import com.airbnb.epoxy.VisibilityState
+import im.vector.app.core.epoxy.LoadingItem_
+import im.vector.app.core.epoxy.TimelineEmptyItem_
+import im.vector.app.features.call.webrtc.WebRtcCallManager
+import im.vector.app.features.home.room.detail.UnreadState
+import im.vector.app.features.home.room.detail.timeline.TimelineEventController
+import im.vector.app.features.home.room.detail.timeline.item.CallTileTimelineItem
+import im.vector.app.features.home.room.detail.timeline.item.ItemWithEvents
+import im.vector.app.features.home.room.detail.timeline.item.TimelineReadMarkerItem_
+import im.vector.app.features.settings.VectorPreferences
+import org.matrix.android.sdk.api.session.room.timeline.Timeline
+import kotlin.reflect.KMutableProperty0
+
+private const val DEFAULT_PREFETCH_THRESHOLD = 30
+
+class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMutableProperty0,
+ private val adapterPositionMapping: MutableMap,
+ private val vectorPreferences: VectorPreferences,
+ private val callManager: WebRtcCallManager
+) {
+
+ private var previousModelsSize = 0
+
+ // Update position when we are building new items
+ fun intercept(
+ models: MutableList>,
+ unreadState: UnreadState,
+ timeline: Timeline?,
+ callback: TimelineEventController.Callback?
+ ) {
+ positionOfReadMarker.set(null)
+ adapterPositionMapping.clear()
+ val callIds = mutableSetOf()
+
+ // Add some prefetch loader if needed
+ models.addBackwardPrefetchIfNeeded(timeline, callback)
+ models.addForwardPrefetchIfNeeded(timeline, callback)
+
+ val modelsIterator = models.listIterator()
+ val showHiddenEvents = vectorPreferences.shouldShowHiddenEvents()
+ var index = 0
+ val firstUnreadEventId = (unreadState as? UnreadState.HasUnread)?.firstUnreadEventId
+ // Then iterate on models so we have the exact positions in the adapter
+ modelsIterator.forEach { epoxyModel ->
+ if (epoxyModel is ItemWithEvents) {
+ epoxyModel.getEventIds().forEach { eventId ->
+ adapterPositionMapping[eventId] = index
+ if (eventId == firstUnreadEventId) {
+ modelsIterator.addReadMarkerItem(callback)
+ index++
+ positionOfReadMarker.set(index)
+ }
+ }
+ }
+ if (epoxyModel is CallTileTimelineItem) {
+ modelsIterator.removeCallItemIfNeeded(epoxyModel, callIds, showHiddenEvents)
+ }
+ index++
+ }
+ previousModelsSize = models.size
+ }
+
+ private fun MutableListIterator>.addReadMarkerItem(callback: TimelineEventController.Callback?) {
+ val readMarker = TimelineReadMarkerItem_()
+ .also {
+ it.id("read_marker")
+ it.setOnVisibilityStateChanged(ReadMarkerVisibilityStateChangedListener(callback))
+ }
+ add(readMarker)
+ // Use next as we still have some process to do before the next iterator loop
+ next()
+ }
+
+ private fun MutableListIterator>.removeCallItemIfNeeded(
+ epoxyModel: CallTileTimelineItem,
+ callIds: MutableSet,
+ showHiddenEvents: Boolean
+ ) {
+ val callId = epoxyModel.attributes.callId
+ // We should remove the call tile if we already have one for this call or
+ // if this is an active call tile without an actual call (which can happen with permalink)
+ val shouldRemoveCallItem = callIds.contains(callId)
+ || (!callManager.getAdvertisedCalls().contains(callId) && epoxyModel.attributes.callStatus.isActive())
+ if (shouldRemoveCallItem && !showHiddenEvents) {
+ remove()
+ val emptyItem = TimelineEmptyItem_()
+ .id(epoxyModel.id())
+ .eventId(epoxyModel.attributes.informationData.eventId)
+ add(emptyItem)
+ }
+ callIds.add(callId)
+ }
+
+ private fun MutableList>.addBackwardPrefetchIfNeeded(timeline: Timeline?, callback: TimelineEventController.Callback?) {
+ val shouldAddBackwardPrefetch = timeline?.hasMoreToLoad(Timeline.Direction.BACKWARDS) ?: false
+ if (shouldAddBackwardPrefetch) {
+ val indexOfPrefetchBackward = (previousModelsSize - 1)
+ .coerceAtMost(size - DEFAULT_PREFETCH_THRESHOLD)
+ .coerceAtLeast(0)
+
+ val loadingItem = LoadingItem_()
+ .id("prefetch_backward_loading${System.currentTimeMillis()}")
+ .showLoader(false)
+ .setVisibilityStateChangedListener(Timeline.Direction.BACKWARDS, callback)
+
+ add(indexOfPrefetchBackward, loadingItem)
+ }
+ }
+
+ private fun MutableList>.addForwardPrefetchIfNeeded(timeline: Timeline?, callback: TimelineEventController.Callback?) {
+ val shouldAddForwardPrefetch = timeline?.hasMoreToLoad(Timeline.Direction.FORWARDS) ?: false
+ if (shouldAddForwardPrefetch) {
+ val indexOfPrefetchForward = DEFAULT_PREFETCH_THRESHOLD.coerceAtMost(size - 1)
+ val loadingItem = LoadingItem_()
+ .id("prefetch_forward_loading${System.currentTimeMillis()}")
+ .showLoader(false)
+ .setVisibilityStateChangedListener(Timeline.Direction.FORWARDS, callback)
+ add(indexOfPrefetchForward, loadingItem)
+ }
+ }
+
+ private fun LoadingItem_.setVisibilityStateChangedListener(
+ direction: Timeline.Direction,
+ callback: TimelineEventController.Callback?
+ ): LoadingItem_ {
+ return onVisibilityStateChanged { _, _, visibilityState ->
+ if (visibilityState == VisibilityState.VISIBLE) {
+ callback?.onLoadMore(direction)
+ }
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt
index e617489902..13bb6db6ef 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt
@@ -32,7 +32,7 @@ import im.vector.app.core.utils.DimensionConverter
/**
* Children must override getViewType()
*/
-abstract class BaseEventItem : VectorEpoxyModel() {
+abstract class BaseEventItem : VectorEpoxyModel(), ItemWithEvents {
// To use for instance when opening a permalink with an eventId
@EpoxyAttribute
@@ -53,12 +53,6 @@ abstract class BaseEventItem : VectorEpoxyModel
holder.checkableBackground.isChecked = highlighted
}
- /**
- * Returns the eventIds associated with the EventItem.
- * Will generally get only one, but it handles the merging items.
- */
- abstract fun getEventIds(): List
-
abstract class BaseHolder(@IdRes val stubId: Int) : VectorEpoxyHolder() {
val leftGuideline by bind(R.id.messageStartGuideline)
val checkableBackground by bind(R.id.messageSelectedBackground)
diff --git a/vector/src/main/java/im/vector/app/core/epoxy/EmptyItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/ItemWithEvents.kt
similarity index 65%
rename from vector/src/main/java/im/vector/app/core/epoxy/EmptyItem.kt
rename to vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/ItemWithEvents.kt
index aaf870667b..cf4211bb2c 100644
--- a/vector/src/main/java/im/vector/app/core/epoxy/EmptyItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/ItemWithEvents.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 New Vector Ltd
+ * Copyright (c) 2021 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package im.vector.app.core.epoxy
+package im.vector.app.features.home.room.detail.timeline.item
-import com.airbnb.epoxy.EpoxyModelClass
-import im.vector.app.R
-
-@EpoxyModelClass(layout = R.layout.item_empty)
-abstract class EmptyItem : VectorEpoxyModel() {
- class Holder : VectorEpoxyHolder()
+interface ItemWithEvents {
+ /**
+ * Returns the eventIds associated with the EventItem.
+ * Will generally get only one, but it handles the merged items.
+ */
+ fun getEventIds(): List
}
diff --git a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt
index 49cb75c9d6..80af64d9f3 100644
--- a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt
@@ -38,6 +38,7 @@ import org.matrix.android.sdk.api.auth.UserPasswordAuth
import timber.log.Timber
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
data class DeactivateAccountViewState(
val passwordShown: Boolean = false
@@ -64,7 +65,7 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v
if (pendingAuth != null) {
uiaContinuation?.resume(pendingAuth!!)
} else {
- uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException())))
+ uiaContinuation?.resumeWithException(IllegalArgumentException())
}
}
is DeactivateAccountAction.PasswordAuthDone -> {
@@ -79,7 +80,7 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v
}
DeactivateAccountAction.ReAuthCancelled -> {
Timber.d("## UIA - Reauth cancelled")
- uiaContinuation?.resumeWith(Result.failure((Exception())))
+ uiaContinuation?.resumeWithException(Exception())
uiaContinuation = null
pendingAuth = null
}
@@ -98,13 +99,15 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v
viewModelScope.launch {
val event = try {
session.deactivateAccount(
+ action.eraseAllData,
object : UserInteractiveAuthInterceptor {
override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation) {
_viewEvents.post(DeactivateAccountViewEvents.RequestReAuth(flowResponse, errCode))
pendingAuth = DefaultBaseAuth(session = flowResponse.session)
uiaContinuation = promise
}
- }, action.eraseAllData)
+ }
+ )
DeactivateAccountViewEvents.Done
} catch (failure: Exception) {
if (failure.isInvalidUIAAuth()) {
diff --git a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt
index 566dea2cd4..8bdf97b6ec 100644
--- a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt
@@ -49,6 +49,7 @@ import org.matrix.android.sdk.rx.rx
import timber.log.Timber
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
class CrossSigningSettingsViewModel @AssistedInject constructor(
@Assisted private val initialState: CrossSigningSettingsViewState,
@@ -130,7 +131,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
if (pendingAuth != null) {
uiaContinuation?.resume(pendingAuth!!)
} else {
- uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException())))
+ uiaContinuation?.resumeWithException(IllegalArgumentException())
}
}
is CrossSigningSettingsAction.PasswordAuthDone -> {
@@ -146,7 +147,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor(
CrossSigningSettingsAction.ReAuthCancelled -> {
Timber.d("## UIA - Reauth cancelled")
_viewEvents.post(CrossSigningSettingsViewEvents.HideModalWaitingView)
- uiaContinuation?.resumeWith(Result.failure((Exception())))
+ uiaContinuation?.resumeWithException(Exception())
uiaContinuation = null
pendingAuth = null
}
diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt
index a56a7b8d48..c48b08e806 100644
--- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt
@@ -64,6 +64,7 @@ import java.util.concurrent.TimeUnit
import javax.net.ssl.HttpsURLConnection
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
data class DevicesViewState(
val myDeviceId: String = "",
@@ -217,7 +218,7 @@ class DevicesViewModel @AssistedInject constructor(
if (pendingAuth != null) {
uiaContinuation?.resume(pendingAuth!!)
} else {
- uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException())))
+ uiaContinuation?.resumeWithException(IllegalArgumentException())
}
Unit
}
@@ -235,7 +236,7 @@ class DevicesViewModel @AssistedInject constructor(
DevicesAction.ReAuthCancelled -> {
Timber.d("## UIA - Reauth cancelled")
// _viewEvents.post(DevicesViewEvents.Loading)
- uiaContinuation?.resumeWith(Result.failure((Exception())))
+ uiaContinuation?.resumeWithException(Exception())
uiaContinuation = null
pendingAuth = null
}
diff --git a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt
index a1d4d6227b..89d632b813 100644
--- a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt
@@ -46,6 +46,7 @@ import org.matrix.android.sdk.rx.rx
import timber.log.Timber
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
class ThreePidsSettingsViewModel @AssistedInject constructor(
@Assisted initialState: ThreePidsSettingsViewState,
@@ -140,7 +141,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
if (pendingAuth != null) {
uiaContinuation?.resume(pendingAuth!!)
} else {
- uiaContinuation?.resumeWith(Result.failure((IllegalArgumentException())))
+ uiaContinuation?.resumeWithException(IllegalArgumentException())
}
}
is ThreePidsSettingsAction.PasswordAuthDone -> {
@@ -155,7 +156,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor(
}
ThreePidsSettingsAction.ReAuthCancelled -> {
Timber.d("## UIA - Reauth cancelled")
- uiaContinuation?.resumeWith(Result.failure((Exception())))
+ uiaContinuation?.resumeWithException(Exception())
uiaContinuation = null
pendingAuth = null
}
diff --git a/vector/src/main/res/layout/item_empty.xml b/vector/src/main/res/layout/item_timeline_empty.xml
similarity index 100%
rename from vector/src/main/res/layout/item_empty.xml
rename to vector/src/main/res/layout/item_timeline_empty.xml
diff --git a/vector/src/main/res/values/attrs.xml b/vector/src/main/res/values/attrs.xml
index 41b8080fc0..0b9852634d 100644
--- a/vector/src/main/res/values/attrs.xml
+++ b/vector/src/main/res/values/attrs.xml
@@ -1,55 +1,52 @@
-
+
+
+
+
-
-
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
-
-
+
+
+
+
-
-
-
-
+
-
+
+
-
-
+
+
-
-
+
+
+
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
@@ -70,16 +67,16 @@
-
+
-
-
-
+
+
+
diff --git a/vector/src/main/res/values/colors_riotx.xml b/vector/src/main/res/values/colors.xml
similarity index 72%
rename from vector/src/main/res/values/colors_riotx.xml
rename to vector/src/main/res/values/colors.xml
index 35d0c797b5..e4cfa18461 100644
--- a/vector/src/main/res/values/colors_riotx.xml
+++ b/vector/src/main/res/values/colors.xml
@@ -1,7 +1,115 @@
-
+
+ #70BF56
+ #ff4b55
+ #ff4b55
+ #2f9edb
+
+
+ #ff4b55
+ #FFC7C7C7
+ #FF999999
+
+
+
+
+ #FFFFFFFF
+
+ #FF181B21
+
+ #F000
+
+
+ #FF1A2027
+
+ #03b381
+
+ #03b381
+
+
+ #FF0D0E10
+
+ #FF15171B
+
+ #03b381
+
+
+ #000
+
+ #FF060708
+
+
+
+ #EEEFEF
+
+ #FF61708B
+
+ #FF22262E
+
+
+ @color/riotx_android_secondary_light
+ @color/riotx_android_secondary_dark
+
+
+ @color/riotx_background_light
+ @color/riotx_background_dark
+
+
+ #FFFFFF
+ #FFFFFF
+
+ #903C3C3C
+ #CCDDDDDD
+
+
+
+
+
+
+ #FF2E2F32
+ #FF9E9E9E
+
+ #FF9E9E9E
+ @color/riot_primary_text_color_light
+
+
+ #FFEDF3FF
+ #FFA1B2D1
+
+ #FFA1B2D1
+ @color/riot_primary_text_color_dark
+
+
+ #2f9edb
+ @color/vector_fuchsia_color
+
+
+ #FFF56679
+ #FFFFC666
+ #FFF8E71C
+ #FF7AC9A1
+ #FF9E9E9E
+
+
+ #FFFFFFFF
+ #FFFFFFFF
+ #FF4B55
+ #FF4B55
+ #FF368BD6
+ #61708B
+
+
+
+ #368BD6
+ #368BD6
+
+
+ #368BD6
+ #ff812d
+
+
#FF0DBD8B
@@ -38,7 +146,7 @@
#5c56f5
#74d12c
-
+
#FF000000
#FFFFFFFF
#55000000
@@ -256,6 +364,4 @@
#FFF8E3
#22262E
-
-
-
\ No newline at end of file
+
diff --git a/vector/src/main/res/values/colors_riot.xml b/vector/src/main/res/values/colors_riot.xml
deleted file mode 100644
index 2f9d521351..0000000000
--- a/vector/src/main/res/values/colors_riot.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-
-
-
-
- #70BF56
- #ff4b55
- #ff4b55
- #2f9edb
-
-
- #ff4b55
- #FFC7C7C7
- #FF999999
-
-
-
-
- #FFFFFFFF
-
- #FF181B21
-
- #F000
-
-
- #FF1A2027
-
- #03b381
-
- #03b381
-
-
- #FF0D0E10
-
- #FF15171B
-
- #03b381
-
-
- #000
-
- #FF060708
-
-
-
- #EEEFEF
-
- #FF61708B
-
- #FF22262E
-
-
- @color/riotx_android_secondary_light
- @color/riotx_android_secondary_dark
-
-
- @color/riotx_background_light
- @color/riotx_background_dark
-
-
- #FFFFFF
- #FFFFFF
-
- #903C3C3C
- #CCDDDDDD
-
-
-
-
-
-
- #FF2E2F32
- #FF9E9E9E
-
- #FF9E9E9E
- @color/riot_primary_text_color_light
-
-
- #FFEDF3FF
- #FFA1B2D1
-
- #FFA1B2D1
- @color/riot_primary_text_color_dark
-
-
- #2f9edb
- @color/vector_fuchsia_color
-
-
- #FFF56679
- #FFFFC666
- #FFF8E71C
- #FF7AC9A1
- #FF9E9E9E
-
-
- #FFFFFFFF
- #FFFFFFFF
- #FF4B55
- #FF4B55
- #FF368BD6
- #61708B
-
-
-
- #368BD6
- #368BD6
-
-
- #368BD6
- #ff812d
-
-