diff --git a/CHANGES.md b/CHANGES.md index 5e0467aa9398530c5f658beb434cb0833b65da67..15302c1a2184aebb196e6a7bc0b1293e3880f841 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,30 @@ Please also refer to the Changelog of Element Android: https://github.com/vector-im/element-android/blob/main/CHANGES.md +Changes in Matrix-SDK 1.4.25 (2022-06-29) +=================================================== + +Imported from Element 1.4.25. (https://github.com/vector-im/element-android/releases/tag/v1.4.25) + +SDK API changes âš ï¸ +------------------ +- Some methods from `Session` have been moved to a new `SyncService`, that you can retrieve from a `Session`. +- `SyncStatusService` method has been moved to the new `SyncService` +- `InitSyncStep` have been moved and renamed to `InitialSyncStep` +- `SyncStatusService.Status` has been renamed to `SyncRequestState` +- The existing `SyncService` has been renamed to `SyncAndroidService` because of name clash with the new SDK Service ([#6029](https://github.com/vector-im/element-android/issues/6029)) +- Allows `AuthenticationService.getLoginFlow` to fail without resetting state from previously successful calls ([#6093](https://github.com/vector-im/element-android/issues/6093)) +- Allows new passwords to be passed at the point of confirmation when resetting a password ([#6169](https://github.com/vector-im/element-android/issues/6169)) +- Notifies other devices when a verification request sent from an Android device is accepted.` ([#5724](https://github.com/vector-im/element-android/issues/5724)) +- Some `val` have been changed to `fun` to increase their visibility in the generated documentation. Just add `()` if you were using them. +- `KeysBackupService.state` has been replaced by `KeysBackupService.getState()` +- `KeysBackupService.isStucked` has been replaced by `KeysBackupService.isStuck()` +- SDK documentation improved ([#5952](https://github.com/vector-im/element-android/issues/5952)) +- Improve replay attacks and reduce duplicate message index errors ([#6077](https://github.com/vector-im/element-android/issues/6077)) +- Remove `RoomSummaryQueryParams.roomId`. If you need to observe a single room, use the new API `RoomService.getRoomSummaryLive(roomId: String)` +- `ActiveSpaceFilter` has been renamed to `SpaceFilter` +- `RoomCategoryFilter.ALL` has been removed, just pass `null` to not filter on Room category. ([#6143](https://github.com/vector-im/element-android/issues/6143)) + + Changes in Matrix-SDK 1.4.16 (2022-05-23) =================================================== diff --git a/dependencies.gradle b/dependencies.gradle index 10f9539e5ac16392be44fd7774c8c397411f9216..451ad4449bc026db99e0f5852244dc49172b1e28 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,10 +7,13 @@ ext.versions = [ 'targetCompat' : JavaVersion.VERSION_11, ] -def gradle = "7.2.0" + +// Pinned to 7.1.3 because of https://github.com/vector-im/element-android/issues/6142 +// Please test carefully before upgrading again. +def gradle = "7.1.3" // Ref: https://kotlinlang.org/releases.html def kotlin = "1.6.21" -def kotlinCoroutines = "1.6.1" +def kotlinCoroutines = "1.6.2" def dagger = "2.42" def retrofit = "2.9.0" def arrow = "0.8.2" @@ -23,7 +26,7 @@ def mavericks = "2.6.1" def glide = "4.13.2" def bigImageViewer = "1.8.1" def jjwt = "0.11.5" -def vanniktechEmoji = "0.9.0" +def vanniktechEmoji = "0.15.0" // Testing def mockk = "1.12.4" @@ -45,12 +48,13 @@ ext.libs = [ 'coroutinesTest' : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines" ], androidx : [ - 'appCompat' : "androidx.appcompat:appcompat:1.4.1", - 'core' : "androidx.core:core-ktx:1.7.0", + 'activity' : "androidx.activity:activity:1.4.0", + 'appCompat' : "androidx.appcompat:appcompat:1.4.2", + 'core' : "androidx.core:core-ktx:1.8.0", 'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1", 'exifinterface' : "androidx.exifinterface:exifinterface:1.3.3", 'fragmentKtx' : "androidx.fragment:fragment-ktx:1.4.1", - 'constraintLayout' : "androidx.constraintlayout:constraintlayout:2.1.3", + 'constraintLayout' : "androidx.constraintlayout:constraintlayout:2.1.4", 'work' : "androidx.work:work-runtime-ktx:2.7.1", 'autoFill' : "androidx.autofill:autofill:1.1.0", 'preferenceKtx' : "androidx.preference:preference-ktx:1.2.0", @@ -69,10 +73,12 @@ ext.libs = [ 'testRules' : "androidx.test:rules:$androidxTest", 'espressoCore' : "androidx.test.espresso:espresso-core:$espresso", 'espressoContrib' : "androidx.test.espresso:espresso-contrib:$espresso", - 'espressoIntents' : "androidx.test.espresso:espresso-intents:$espresso" + 'espressoIntents' : "androidx.test.espresso:espresso-intents:$espresso", + 'viewpager2' : "androidx.viewpager2:viewpager2:1.0.0", + 'transition' : "androidx.transition:transition:1.2.0", ], google : [ - 'material' : "com.google.android.material:material:1.6.0" + 'material' : "com.google.android.material:material:1.6.1" ], dagger : [ 'dagger' : "com.google.dagger:dagger:$dagger", @@ -81,7 +87,7 @@ ext.libs = [ 'hiltCompiler' : "com.google.dagger:hilt-compiler:$dagger" ], squareup : [ - 'moshi' : "com.squareup.moshi:moshi-adapters:$moshi", + 'moshi' : "com.squareup.moshi:moshi:$moshi", 'moshiKotlin' : "com.squareup.moshi:moshi-kotlin-codegen:$moshi", 'retrofit' : "com.squareup.retrofit2:retrofit:$retrofit", 'retrofitMoshi' : "com.squareup.retrofit2:converter-moshi:$retrofit" @@ -107,6 +113,10 @@ ext.libs = [ 'mavericks' : "com.airbnb.android:mavericks:$mavericks", 'mavericksTesting' : "com.airbnb.android:mavericks-testing:$mavericks" ], + maplibre : [ + 'androidSdk' : "org.maplibre.gl:android-sdk:9.5.2", + 'pluginAnnotation' : "org.maplibre.gl:android-plugin-annotation-v9:1.0.0" + ], mockk : [ 'mockk' : "io.mockk:mockk:$mockk", 'mockkAndroid' : "io.mockk:mockk-android:$mockk" diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle index 76869fccf1c70d38dcafb076c1b239498b3a8fea..59cefe7e899545202918938527213805f5982217 100644 --- a/dependencies_groups.gradle +++ b/dependencies_groups.gradle @@ -141,7 +141,6 @@ ext.groups = [ 'jline', 'jp.wasabeef', 'junit', - 'me.leolin', 'me.saket', 'net.bytebuddy', 'net.java', diff --git a/gradle.properties b/gradle.properties index 97384e645c0a6dbdf353943d4d298f288515ce73..fc230026271373424a89d4e1cc904f4cf48bcc7d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,7 +26,7 @@ vector.httpLogLevel=NONE # Ref: https://github.com/vanniktech/gradle-maven-publish-plugin GROUP=org.matrix.android POM_ARTIFACT_ID=matrix-android-sdk2 -VERSION_NAME=1.4.16 +VERSION_NAME=1.4.25 POM_PACKAGING=aar diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index d04a675cbaa67e173db8b91b14a0622e057d27c3..f6a7a294de26955a5ed883525332809aea9a93f4 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -77,6 +77,7 @@ android { buildTypes { debug { + testCoverageEnabled true // Set to true to log privacy or sensible data, such as token buildConfigField "boolean", "LOG_PRIVATE_DATA", project.property("vector.debugPrivateData") // Set to BODY instead of NONE to enable logging @@ -139,7 +140,6 @@ dependencies { implementation libs.jetbrains.coroutinesCore implementation libs.jetbrains.coroutinesAndroid - implementation libs.androidx.appCompat implementation libs.androidx.core // Lifecycle @@ -155,15 +155,14 @@ dependencies { // - https://github.com/square/okhttp/issues/3278 // - https://github.com/square/okhttp/issues/4455 // - https://github.com/square/okhttp/issues/3146 - implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3")) + implementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0")) implementation 'com.squareup.okhttp3:okhttp' implementation 'com.squareup.okhttp3:logging-interceptor' - implementation 'com.squareup.okhttp3:okhttp-urlconnection' implementation libs.squareup.moshi kapt libs.squareup.moshiKotlin - implementation libs.markwon.core + api "com.atlassian.commonmark:commonmark:0.13.0" // Image implementation libs.androidx.exifinterface @@ -179,12 +178,8 @@ dependencies { // Work implementation libs.androidx.work - // FP - implementation libs.arrow.core - implementation libs.arrow.instances - // olm lib is now hosted in MavenCentral - implementation 'org.matrix.android:olm-sdk:3.2.11' + implementation 'org.matrix.android:olm-sdk:3.2.12' // DI implementation libs.dagger.dagger @@ -201,11 +196,9 @@ dependencies { implementation libs.apache.commonsImaging // Phone number https://github.com/google/libphonenumber - implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.48' + implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.50' testImplementation libs.tests.junit - testImplementation 'org.robolectric:robolectric:4.7.3' - //testImplementation 'org.robolectric:shadows-support-v4:3.0' // Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281 testImplementation libs.mockk.mockk testImplementation libs.tests.kluent diff --git a/matrix-sdk-android/docs/packages.md b/matrix-sdk-android/docs/packages.md index ae7bee1b4e0c8fb954fc39629e87dc79aafa26fd..19f7c15a7a557396dc08ca7e8aa2df5340b4de93 100644 --- a/matrix-sdk-android/docs/packages.md +++ b/matrix-sdk-android/docs/packages.md @@ -1,3 +1,7 @@ +# Package org.matrix.android.sdk.userstories + +This package contains some user stories (**Us** prefix) of the SDK usage. You will find example of what it is possible to do with the SDK and the API which can be used to do it. + # Package org.matrix.android.sdk.api This is the root package of the API exposed by this SDK. diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/InstrumentedTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/InstrumentedTest.kt index a76376682107df2000398d66e5281b4e99e4ef73..f08f0a28ed1569cf86b0e8f345cc3d8fe1b771d1 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/InstrumentedTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/InstrumentedTest.kt @@ -19,10 +19,14 @@ package org.matrix.android.sdk import android.content.Context import androidx.test.core.app.ApplicationProvider import org.junit.Rule +import org.matrix.android.sdk.common.RetryTestRule import org.matrix.android.sdk.test.shared.createTimberTestRule interface InstrumentedTest { + @Rule + fun retryTestRule() = RetryTestRule(3) + @Rule fun timberTestRule() = createTimberTestRule() diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/Util.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/Util.kt new file mode 100644 index 0000000000000000000000000000000000000000..5e2c2ba25fe84b05c064433168c07d66ad07e2bb --- /dev/null +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/Util.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk + +import junit.framework.TestCase.fail + +/** + * Will fail the test if invoking [block] is not throwing a Throwable. + * + * @param message the failure message, if the block does not throw any Throwable + * @param failureBlock a Lambda to be able to do extra check on the thrown Throwable + * @param block the block to test + */ +internal suspend fun mustFail( + message: String = "must fail", + failureBlock: ((Throwable) -> Unit)? = null, + block: suspend () -> Unit, +) { + val isSuccess = try { + block.invoke() + true + } catch (throwable: Throwable) { + failureBlock?.invoke(throwable) + false + } + + if (isSuccess) { + fail(message) + } +} diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/AccountCreationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/AccountCreationTest.kt index 486bc0276950b0a50195818ac3e20984cf00effc..7e4fc4768fba85909885f3e7faeb506a267ef7e8 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/AccountCreationTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/AccountCreationTest.kt @@ -24,8 +24,8 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.TestConstants @@ -34,32 +34,22 @@ import org.matrix.android.sdk.common.TestConstants @LargeTest class AccountCreationTest : InstrumentedTest { - private val commonTestHelper = CommonTestHelper(context()) - private val cryptoTestHelper = CryptoTestHelper(commonTestHelper) - @Test - fun createAccountTest() { - val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true)) - - commonTestHelper.signOutAndClose(session) + fun createAccountTest() = runSessionTest(context()) { commonTestHelper -> + commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true)) } @Test @Ignore("This test will be ignored until it is fixed") - fun createAccountAndLoginAgainTest() { + fun createAccountAndLoginAgainTest() = runSessionTest(context()) { commonTestHelper -> val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true)) // Log again to the same account - val session2 = commonTestHelper.logIntoAccount(session.myUserId, SessionTestParams(withInitialSync = true)) - - commonTestHelper.signOutAndClose(session) - commonTestHelper.signOutAndClose(session2) + commonTestHelper.logIntoAccount(session.myUserId, SessionTestParams(withInitialSync = true)) } @Test - fun simpleE2eTest() { - val res = cryptoTestHelper.doE2ETestWithAliceInARoom() - - res.cleanUp(commonTestHelper) + fun simpleE2eTest() = runCryptoTest(context()) { cryptoTestHelper, _ -> + cryptoTestHelper.doE2ETestWithAliceInARoom() } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt index 6d740c5a3421c5668b3fb13c5583f69ebe980944..260e8dbe058bb7d73ee87d1409fcd61cfa8cde8b 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/ChangePasswordTest.kt @@ -25,7 +25,7 @@ import org.junit.runners.JUnit4 import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.failure.isInvalidPassword -import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.TestConstants @@ -34,14 +34,12 @@ import org.matrix.android.sdk.common.TestConstants @Ignore("This test will be ignored until it is fixed") class ChangePasswordTest : InstrumentedTest { - private val commonTestHelper = CommonTestHelper(context()) - companion object { private const val NEW_PASSWORD = "this is a new password" } @Test - fun changePasswordTest() { + fun changePasswordTest() = runSessionTest(context()) { commonTestHelper -> val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = false)) // Change password @@ -54,9 +52,6 @@ class ChangePasswordTest : InstrumentedTest { throwable.isInvalidPassword().shouldBeTrue() // Try to login with the new password, should work - val session2 = commonTestHelper.logIntoAccount(session.myUserId, NEW_PASSWORD, SessionTestParams(withInitialSync = false)) - - commonTestHelper.signOutAndClose(session) - commonTestHelper.signOutAndClose(session2) + commonTestHelper.logIntoAccount(session.myUserId, NEW_PASSWORD, SessionTestParams(withInitialSync = false)) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt index d2dfe4d9454b2f02d44602a39b185398deb29054..0b21f85742d513bfac201c648958a4990e8b099f 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt @@ -29,7 +29,7 @@ import org.matrix.android.sdk.api.auth.UserPasswordAuth import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.MatrixError -import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.TestConstants import kotlin.coroutines.Continuation @@ -39,10 +39,8 @@ import kotlin.coroutines.resume @FixMethodOrder(MethodSorters.JVM) class DeactivateAccountTest : InstrumentedTest { - private val commonTestHelper = CommonTestHelper(context()) - @Test - fun deactivateAccountTest() { + fun deactivateAccountTest() = runSessionTest(context(), false /* session will be deactivated */) { commonTestHelper -> val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true)) // Deactivate the account diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/network/ApiInterceptorTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/network/ApiInterceptorTest.kt index 9371154aaf0aee016ab47dfccadc11e126aab846..8dbff82015791b6fa43f92d94e38eb85d542f28f 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/network/ApiInterceptorTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/network/ApiInterceptorTest.kt @@ -23,7 +23,7 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest -import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.TestConstants import timber.log.Timber @@ -32,10 +32,8 @@ import timber.log.Timber @FixMethodOrder(MethodSorters.JVM) class ApiInterceptorTest : InstrumentedTest { - private val commonTestHelper = CommonTestHelper(context()) - @Test - fun apiInterceptorTest() { + fun apiInterceptorTest() = runSessionTest(context()) { commonTestHelper -> val responses = mutableListOf<String>() val listener = object : ApiInterceptorListener { diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt index e33e4faea2920db2b6e75956254bcb42dac6eff5..7dafe33935f0c84baec58743f05208b1d4d9266e 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt @@ -54,12 +54,39 @@ import java.util.concurrent.TimeUnit * This class exposes methods to be used in common cases * Registration, login, Sync, Sending messages... */ -class CommonTestHelper(context: Context) { +class CommonTestHelper private constructor(context: Context) { + + companion object { + internal fun runSessionTest(context: Context, autoSignoutOnClose: Boolean = true, block: (CommonTestHelper) -> Unit) { + val testHelper = CommonTestHelper(context) + return try { + block(testHelper) + } finally { + if (autoSignoutOnClose) { + testHelper.cleanUpOpenedSessions() + } + } + } + + internal fun runCryptoTest(context: Context, autoSignoutOnClose: Boolean = true, block: (CryptoTestHelper, CommonTestHelper) -> Unit) { + val testHelper = CommonTestHelper(context) + val cryptoTestHelper = CryptoTestHelper(testHelper) + return try { + block(cryptoTestHelper, testHelper) + } finally { + if (autoSignoutOnClose) { + testHelper.cleanUpOpenedSessions() + } + } + } + } internal val matrix: TestMatrix private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) private var accountNumber = 0 + private val trackedSessions = mutableListOf<Session>() + fun getTestInterceptor(session: Session): MockOkHttpInterceptor? = TestModule.interceptorForSession(session.sessionId) as? MockOkHttpInterceptor init { @@ -84,6 +111,15 @@ class CommonTestHelper(context: Context) { return logIntoAccount(userId, TestConstants.PASSWORD, testParams) } + fun cleanUpOpenedSessions() { + trackedSessions.forEach { + runBlockingTest { + it.signOutService().signOut(true) + } + } + trackedSessions.clear() + } + /** * Create a homeserver configuration, with Http connection allowed for test */ @@ -96,16 +132,16 @@ class CommonTestHelper(context: Context) { /** * This methods init the event stream and check for initial sync * - * @param session the session to sync + * @param session the session to sync */ fun syncSession(session: Session, timeout: Long = TestConstants.timeOutMillis * 10) { val lock = CountDownLatch(1) coroutineScope.launch { - session.startSync(true) - val syncLiveData = session.getSyncStateLive() + session.syncService().startSync(true) + val syncLiveData = session.syncService().getSyncStateLive() val syncObserver = object : Observer<SyncState> { override fun onChanged(t: SyncState?) { - if (session.hasAlreadySynced()) { + if (session.syncService().hasAlreadySynced()) { lock.countDown() syncLiveData.removeObserver(this) } @@ -119,15 +155,15 @@ class CommonTestHelper(context: Context) { /** * This methods clear the cache and waits for initialSync * - * @param session the session to sync + * @param session the session to sync */ fun clearCacheAndSync(session: Session, timeout: Long = TestConstants.timeOutMillis) { waitWithLatch(timeout) { latch -> session.clearCache() - val syncLiveData = session.getSyncStateLive() + val syncLiveData = session.syncService().getSyncStateLive() val syncObserver = object : Observer<SyncState> { override fun onChanged(t: SyncState?) { - if (session.hasAlreadySynced()) { + if (session.syncService().hasAlreadySynced()) { Timber.v("Clear cache and synced") syncLiveData.removeObserver(this) latch.countDown() @@ -135,15 +171,15 @@ class CommonTestHelper(context: Context) { } } syncLiveData.observeForever(syncObserver) - session.startSync(true) + session.syncService().startSync(true) } } /** * Sends text messages in a room * - * @param room the room where to send the messages - * @param message the message to send + * @param room the room where to send the messages + * @param message the message to send * @param nbOfMessages the number of time the message will be sent */ fun sendTextMessage(room: Room, message: String, nbOfMessages: Int, timeout: Long = TestConstants.timeOutMillis): List<TimelineEvent> { @@ -207,8 +243,8 @@ class CommonTestHelper(context: Context) { /** * Reply in a thread - * @param room the room where to send the messages - * @param message the message to send + * @param room the room where to send the messages + * @param message the message to send * @param numberOfMessages the number of time the message will be sent */ fun replyInThreadMessage( @@ -216,7 +252,8 @@ class CommonTestHelper(context: Context) { message: String, numberOfMessages: Int, rootThreadEventId: String, - timeout: Long = TestConstants.timeOutMillis): List<TimelineEvent> { + timeout: Long = TestConstants.timeOutMillis + ): List<TimelineEvent> { val timeline = room.timelineService().createTimeline(null, TimelineSettings(10)) timeline.start() val sentEvents = sendTextMessagesBatched(timeline, room, message, numberOfMessages, timeout, rootThreadEventId) @@ -232,48 +269,58 @@ class CommonTestHelper(context: Context) { * Creates a unique account * * @param userNamePrefix the user name prefix - * @param password the password - * @param testParams test params about the session + * @param password the password + * @param testParams test params about the session * @return the session associated with the newly created account */ - private fun createAccount(userNamePrefix: String, - password: String, - testParams: SessionTestParams): Session { + private fun createAccount( + userNamePrefix: String, + password: String, + testParams: SessionTestParams + ): Session { val session = createAccountAndSync( userNamePrefix + "_" + accountNumber++ + "_" + UUID.randomUUID(), password, testParams ) assertNotNull(session) - return session + return session.also { + trackedSessions.add(session) + } } /** * Logs into an existing account * - * @param userId the userId to log in - * @param password the password to log in + * @param userId the userId to log in + * @param password the password to log in * @param testParams test params about the session * @return the session associated with the existing account */ - fun logIntoAccount(userId: String, - password: String, - testParams: SessionTestParams): Session { + fun logIntoAccount( + userId: String, + password: String, + testParams: SessionTestParams + ): Session { val session = logAccountAndSync(userId, password, testParams) assertNotNull(session) - return session + return session.also { + trackedSessions.add(session) + } } /** * Create an account and a dedicated session * - * @param userName the account username - * @param password the password + * @param userName the account username + * @param password the password * @param sessionTestParams parameters for the test */ - private fun createAccountAndSync(userName: String, - password: String, - sessionTestParams: SessionTestParams): Session { + private fun createAccountAndSync( + userName: String, + password: String, + sessionTestParams: SessionTestParams + ): Session { val hs = createHomeServerConfig() runBlockingTest { @@ -297,7 +344,7 @@ class CommonTestHelper(context: Context) { val session = (registrationResult as RegistrationResult.Success).session session.open() if (sessionTestParams.withInitialSync) { - syncSession(session, 60_000) + syncSession(session, 120_000) } return session } @@ -305,13 +352,15 @@ class CommonTestHelper(context: Context) { /** * Start an account login * - * @param userName the account username - * @param password the password + * @param userName the account username + * @param password the password * @param sessionTestParams session test params */ - private fun logAccountAndSync(userName: String, - password: String, - sessionTestParams: SessionTestParams): Session { + private fun logAccountAndSync( + userName: String, + password: String, + sessionTestParams: SessionTestParams + ): Session { val hs = createHomeServerConfig() runBlockingTest { @@ -337,8 +386,10 @@ class CommonTestHelper(context: Context) { * @param userName the account username * @param password the password */ - fun logAccountWithError(userName: String, - password: String): Throwable { + fun logAccountWithError( + userName: String, + password: String + ): Throwable { val hs = createHomeServerConfig() runBlockingTest { @@ -378,7 +429,10 @@ class CommonTestHelper(context: Context) { * @throws InterruptedException */ fun await(latch: CountDownLatch, timeout: Long? = TestConstants.timeOutMillis) { - assertTrue(latch.await(timeout ?: TestConstants.timeOutMillis, TimeUnit.MILLISECONDS)) + assertTrue( + "Timed out after " + timeout + "ms waiting for something to happen. See stacktrace for cause.", + latch.await(timeout ?: TestConstants.timeOutMillis, TimeUnit.MILLISECONDS) + ) } suspend fun retryPeriodicallyWithLatch(latch: CountDownLatch, condition: (() -> Boolean)) { @@ -433,6 +487,7 @@ class CommonTestHelper(context: Context) { fun Iterable<Session>.signOutAndClose() = forEach { signOutAndClose(it) } fun signOutAndClose(session: Session) { + trackedSessions.remove(session) runBlockingTest(timeout = 60_000) { session.signOutService().signOut(true) } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestData.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestData.kt index b6bedbd7197eff6d73c3d54a063600b81f463791..41d0d3a7e86810386ee6ddfa2bcf43d2517195e0 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestData.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestData.kt @@ -18,8 +18,10 @@ package org.matrix.android.sdk.common import org.matrix.android.sdk.api.session.Session -data class CryptoTestData(val roomId: String, - val sessions: List<Session>) { +data class CryptoTestData( + val roomId: String, + val sessions: List<Session> +) { val firstSession: Session get() = sessions.first() diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt index 348841313b5f9f5fd6f73d9f551a0c1edfc80f79..5fd86d4fdb87ec58d9d6481ab97138d8cdf79dde 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt @@ -58,7 +58,7 @@ import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.securestorage.EmptyKeySigner -import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService +import org.matrix.android.sdk.api.session.securestorage.KeyRef import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.awaitCallback import org.matrix.android.sdk.api.util.toBase64NoPadding @@ -66,7 +66,7 @@ import java.util.UUID import kotlin.coroutines.Continuation import kotlin.coroutines.resume -class CryptoTestHelper(private val testHelper: CommonTestHelper) { +class CryptoTestHelper(val testHelper: CommonTestHelper) { private val messagesFromAlice: List<String> = listOf("0 - Hello I'm Alice!", "4 - Go!") private val messagesFromBob: List<String> = listOf("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera.") @@ -361,19 +361,19 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) { ssssService.storeSecret( MASTER_KEY_SSSS_NAME, session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.master!!, - listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec)) + listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec)) ) ssssService.storeSecret( SELF_SIGNING_KEY_SSSS_NAME, session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.selfSigned!!, - listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec)) + listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec)) ) ssssService.storeSecret( USER_SIGNING_KEY_SSSS_NAME, session.cryptoService().crossSigningService().getCrossSigningPrivateKeys()!!.user!!, - listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec)) + listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec)) ) // set up megolm backup @@ -390,7 +390,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) { ssssService.storeSecret( KEYBACKUP_SECRET_SSSS_NAME, secret, - listOf(SharedSecretStorageService.KeyRef(keyInfo.keyId, keyInfo.keySpec)) + listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec)) ) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/MockOkHttpInterceptor.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/MockOkHttpInterceptor.kt index b6d833a77cd5d04239969520472ab9ffaa3e5295..6dfee2f18f226119ae2279758f0fb5c2815a8a2a 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/MockOkHttpInterceptor.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/MockOkHttpInterceptor.kt @@ -73,9 +73,11 @@ class MockOkHttpInterceptor : TestInterceptor { /** * Simple rule that reply with the given body for any request that matches the match param */ - class SimpleRule(match: String, - private val code: Int = HttpsURLConnection.HTTP_OK, - private val body: String = "{}") : Rule(match) { + class SimpleRule( + match: String, + private val code: Int = HttpsURLConnection.HTTP_OK, + private val body: String = "{}" + ) : Rule(match) { override fun process(originalRequest: Request): Response? { return Response.Builder() diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/RetryTestRule.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/RetryTestRule.kt index b16ab98e6c9fc69d9af8c91be067e196a7cca7a5..39f49a9ccc3f96b3d13e03f79b3d8fc6099da4c3 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/RetryTestRule.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/RetryTestRule.kt @@ -40,6 +40,9 @@ class RetryTestRule(val retryCount: Int = 3) : TestRule { for (i in 0 until retryCount) { try { base.evaluate() + if (i > 0) { + println("Retried test $i times") + } return } catch (t: Throwable) { caughtThrowable = t diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestConstants.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestConstants.kt index 0f79896b2cd28a6f42bdc7fd19ded9a3a15c1dbf..89c965c31affc59685d4662848cbec6ee1ec74d4 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestConstants.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestConstants.kt @@ -23,7 +23,7 @@ object TestConstants { const val TESTS_HOME_SERVER_URL = "http://10.0.2.2:8080" // Time out to use when waiting for server response. - private const val AWAIT_TIME_OUT_MILLIS = 60_000 + private const val AWAIT_TIME_OUT_MILLIS = 120_000 // Time out to use when waiting for server response, when the debugger is connected. 10 minutes private const val AWAIT_TIME_OUT_WITH_DEBUGGER_MILLIS = 10 * 60_000 diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrix.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrix.kt index e663cc186571b539fbde872f1c10331c1aec5f37..5864a801e654534ca6058978e3b29798beeff055 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrix.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrix.kt @@ -21,7 +21,8 @@ import android.os.Handler import android.os.Looper import androidx.lifecycle.ProcessLifecycleOwner import androidx.work.Configuration -import androidx.work.WorkManager +import androidx.work.impl.WorkManagerImpl +import androidx.work.impl.utils.taskexecutor.WorkManagerTaskExecutor import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.api.MatrixConfiguration @@ -66,7 +67,12 @@ internal class TestMatrix(context: Context, matrixConfiguration: MatrixConfigura .setExecutor(Executors.newCachedThreadPool()) .setWorkerFactory(matrixWorkerFactory) .build() - WorkManager.initialize(appContext, configuration) + val delegate = WorkManagerImpl( + context, + configuration, + WorkManagerTaskExecutor(configuration.taskExecutor) + ) + WorkManagerImpl.setDelegate(delegate) uiHandler.post { ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver) } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixCallback.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixCallback.kt index 9f6d6eb1368fc2e88ec669bc287677b485413fc2..a007d684e326f6df3c9584205814779929ff5707 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixCallback.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixCallback.kt @@ -27,8 +27,10 @@ import java.util.concurrent.CountDownLatch * @param onlySuccessful true to fail if an error occurs. This is the default behavior * @param <T> */ -open class TestMatrixCallback<T>(private val countDownLatch: CountDownLatch, - private val onlySuccessful: Boolean = true) : MatrixCallback<T> { +open class TestMatrixCallback<T>( + private val countDownLatch: CountDownLatch, + private val onlySuccessful: Boolean = true +) : MatrixCallback<T> { @CallSuper override fun onSuccess(data: T) { diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt index 525e168cf1f2a19170d74ba0547a4551e70ff23e..daf6b73313fd900db73e8fde539321714fafba6e 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/TestMatrixComponent.kt @@ -47,7 +47,9 @@ internal interface TestMatrixComponent : MatrixComponent { @Component.Factory interface Factory { - fun create(@BindsInstance context: Context, - @BindsInstance matrixConfiguration: MatrixConfiguration): TestMatrixComponent + fun create( + @BindsInstance context: Context, + @BindsInstance matrixConfiguration: MatrixConfiguration + ): TestMatrixComponent } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt index f5f585a1e0c9f6e4daa9194220962fc5349e8f16..17c7c28d81dffcb80438b4854e44a52d07ef46d3 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt @@ -22,6 +22,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Assert.assertEquals import org.junit.Assert.assertNotEquals import org.junit.FixMethodOrder +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -40,6 +41,7 @@ import java.util.UUID @Suppress("SpellCheckingInspection") @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Ignore class AttachmentEncryptionTest { private fun checkDecryption(input: String, encryptedFileInfo: EncryptedFileInfo): String { diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreTest.kt index e823aa39a1115124acc2daf9d9918e4a834a3bd6..dbc6929e34865bc07d1d28e09a5a6bfae57fef2e 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/CryptoStoreTest.kt @@ -22,9 +22,12 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertNotEquals import org.junit.Assert.assertNull import org.junit.Before +import org.junit.Ignore +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.matrix.android.sdk.InstrumentedTest +import org.matrix.android.sdk.common.RetryTestRule import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.util.time.DefaultClock @@ -35,8 +38,11 @@ import org.matrix.olm.OlmSession private const val DUMMY_DEVICE_KEY = "DeviceKey" @RunWith(AndroidJUnit4::class) +@Ignore class CryptoStoreTest : InstrumentedTest { + @get:Rule val rule = RetryTestRule(3) + private val cryptoStoreHelper = CryptoStoreHelper() private val clock = DefaultClock() diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/DecryptRedactedEventTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/DecryptRedactedEventTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..a48b45a1f53fb78b819c310679fc274dc90aee20 --- /dev/null +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/DecryptRedactedEventTest.kt @@ -0,0 +1,75 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.crypto + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Assert +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.matrix.android.sdk.InstrumentedTest +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.getTimelineEvent +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest + +@RunWith(AndroidJUnit4::class) +@FixMethodOrder(MethodSorters.JVM) +class DecryptRedactedEventTest : InstrumentedTest { + + @Test + fun doNotFailToDecryptRedactedEvent() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> + val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) + val e2eRoomID = testData.roomId + val aliceSession = testData.firstSession + val bobSession = testData.secondSession!! + + val roomALicePOV = aliceSession.getRoom(e2eRoomID)!! + val timelineEvent = testHelper.sendTextMessage(roomALicePOV, "Hello", 1).first() + val redactionReason = "Wrong Room" + roomALicePOV.sendService().redactEvent(timelineEvent.root, redactionReason) + + // get the event from bob + testHelper.waitWithLatch { + testHelper.retryPeriodicallyWithLatch(it) { + bobSession.getRoom(e2eRoomID)?.getTimelineEvent(timelineEvent.eventId)?.root?.isRedacted() == true + } + } + + val eventBobPov = bobSession.getRoom(e2eRoomID)?.getTimelineEvent(timelineEvent.eventId)!! + + testHelper.runBlockingTest { + try { + val result = bobSession.cryptoService().decryptEvent(eventBobPov.root, "") + Assert.assertEquals( + "Unexpected redacted reason", + redactionReason, + result.clearEvent.toModel<Event>()?.unsignedData?.redactedEvent?.content?.get("reason") + ) + Assert.assertEquals( + "Unexpected Redacted event id", + timelineEvent.eventId, + result.clearEvent.toModel<Event>()?.unsignedData?.redactedEvent?.redacts + ) + } catch (failure: Throwable) { + Assert.fail("Should not throw when decrypting a redacted event") + } + } + } +} diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt index ebe4c5ff6fb52e2408650ed722173309a4236712..5a61eee7fe30c238ddfd410e318c9a901999a980 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt @@ -23,6 +23,8 @@ import org.amshove.kluent.fail import org.amshove.kluent.internal.assertEquals import org.junit.Assert import org.junit.FixMethodOrder +import org.junit.Ignore +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @@ -56,17 +58,23 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest +import org.matrix.android.sdk.common.RetryTestRule import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.common.TestMatrixCallback +import org.matrix.android.sdk.mustFail import java.util.concurrent.CountDownLatch @RunWith(JUnit4::class) @FixMethodOrder(MethodSorters.JVM) @LargeTest +@Ignore("This test fails with an unhandled exception thrown from a coroutine which terminates the entire test run.") class E2eeSanityTests : InstrumentedTest { + @get:Rule val rule = RetryTestRule(3) + /** * Simple test that create an e2ee room. * Some new members are added, and a message is sent. @@ -77,9 +85,7 @@ class E2eeSanityTests : InstrumentedTest { * Alice sends a new message, then check that the new one can be decrypted */ @Test - fun testSendingE2EEMessages() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun testSendingE2EEMessages() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val aliceSession = cryptoTestData.firstSession @@ -193,21 +199,12 @@ class E2eeSanityTests : InstrumentedTest { } } } - - otherAccounts.forEach { - testHelper.signOutAndClose(it) - } - newAccount.forEach { testHelper.signOutAndClose(it) } - - cryptoTestData.cleanUp(testHelper) } @Test - fun testKeyGossipingIsEnabledByDefault() { - val testHelper = CommonTestHelper(context()) + fun testKeyGossipingIsEnabledByDefault() = runSessionTest(context()) { testHelper -> val session = testHelper.createAccount("alice", SessionTestParams(true)) Assert.assertTrue("Key gossiping should be enabled by default", session.cryptoService().isKeyGossipingEnabled()) - testHelper.signOutAndClose(session) } /** @@ -225,9 +222,7 @@ class E2eeSanityTests : InstrumentedTest { * 9. Check that new session can decrypt */ @Test - fun testBasicBackupImport() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun testBasicBackupImport() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val aliceSession = cryptoTestData.firstSession @@ -339,8 +334,6 @@ class E2eeSanityTests : InstrumentedTest { // ensure bob can now decrypt cryptoTestHelper.ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText) - - testHelper.signOutAndClose(newBobSession) } /** @@ -348,9 +341,7 @@ class E2eeSanityTests : InstrumentedTest { * get them from an older one. */ @Test - fun testSimpleGossip() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun testSimpleGossip() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val aliceSession = cryptoTestData.firstSession @@ -444,18 +435,13 @@ class E2eeSanityTests : InstrumentedTest { } cryptoTestHelper.ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText) - - cryptoTestData.cleanUp(testHelper) - testHelper.signOutAndClose(newBobSession) } /** * Test that if a better key is forwarded (lower index, it is then used) */ @Test - fun testForwardBetterKey() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun testForwardBetterKey() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val aliceSession = cryptoTestData.firstSession @@ -521,10 +507,8 @@ class E2eeSanityTests : InstrumentedTest { // Confirm we can decrypt one but not the other testHelper.runBlockingTest { - try { + mustFail(message = "Should not be able to decrypt event") { newBobSession.cryptoService().decryptEvent(firstEventNewBobPov.root, "") - fail("Should not be able to decrypt event") - } catch (_: MXCryptoError) { } } @@ -573,10 +557,6 @@ class E2eeSanityTests : InstrumentedTest { canDecryptFirst && canDecryptSecond } } - - testHelper.signOutAndClose(aliceSession) - testHelper.signOutAndClose(bobSessionWithBetterKey) - testHelper.signOutAndClose(newBobSession) } private fun sendMessageInRoom(testHelper: CommonTestHelper, aliceRoomPOV: Room, text: String): String? { @@ -607,9 +587,7 @@ class E2eeSanityTests : InstrumentedTest { * Test that if a better key is forwared (lower index, it is then used) */ @Test - fun testSelfInteractiveVerificationAndGossip() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun testASelfInteractiveVerificationAndGossip() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val aliceSession = testHelper.createAccount("alice", SessionTestParams(true)) cryptoTestHelper.bootstrapSecurity(aliceSession) @@ -648,7 +626,7 @@ class E2eeSanityTests : InstrumentedTest { // we can release this latch? oldCompleteLatch.countDown() } - else -> Unit + else -> Unit } } }) @@ -675,17 +653,17 @@ class E2eeSanityTests : InstrumentedTest { IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> { // no need to accept as there was a request first it will auto accept } - IncomingSasVerificationTransaction.UxState.SHOW_SAS -> { + IncomingSasVerificationTransaction.UxState.SHOW_SAS -> { if (matchOnce) { sasTx.userHasVerifiedShortCode() newCode = sasTx.getDecimalCodeRepresentation() matchOnce = false } } - IncomingSasVerificationTransaction.UxState.VERIFIED -> { + IncomingSasVerificationTransaction.UxState.VERIFIED -> { newCompleteLatch.countDown() } - else -> Unit + else -> Unit } } }) @@ -748,9 +726,6 @@ class E2eeSanityTests : InstrumentedTest { aliceSession.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()!!.version, aliceNewSession.cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()!!.version ) - - testHelper.signOutAndClose(aliceSession) - testHelper.signOutAndClose(aliceNewSession) } private fun ensureMembersHaveJoined(testHelper: CommonTestHelper, aliceSession: Session, otherAccounts: List<Session>, e2eRoomID: String) { diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ExportEncryptionTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ExportEncryptionTest.kt index c2d8f4fb35f30c99457c8b81c2298d1a29b90763..bddb31fc92679510d6f3dda5d3dcfa6d3ab1e7d8 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ExportEncryptionTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ExportEncryptionTest.kt @@ -21,6 +21,7 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Assert.fail import org.junit.FixMethodOrder +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -30,6 +31,7 @@ import org.junit.runners.MethodSorters */ @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Ignore class ExportEncryptionTest { @Test @@ -83,7 +85,8 @@ class ExportEncryptionTest { @Test fun checkExportDecrypt1() { val password = "password" - val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" + "cissyYBxjsfsAndErh065A8=\n-----END MEGOLM SESSION DATA-----" + val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" + + "cissyYBxjsfsAndErh065A8=\n-----END MEGOLM SESSION DATA-----" val expectedString = "plain" var decodedString: String? = null @@ -103,7 +106,8 @@ class ExportEncryptionTest { @Test fun checkExportDecrypt2() { val password = "betterpassword" - val input = "-----BEGIN MEGOLM SESSION DATA-----\nAW1vcmVzYWx0bW9yZXNhbHT//////////wAAAAAAAAAAAAAD6KyBpe1Niv5M5NPm4ZATsJo5nghk\n" + "KYu63a0YQ5DRhUWEKk7CcMkrKnAUiZny\n-----END MEGOLM SESSION DATA-----" + val input = "-----BEGIN MEGOLM SESSION DATA-----\nAW1vcmVzYWx0bW9yZXNhbHT//////////wAAAAAAAAAAAAAD6KyBpe1Niv5M5NPm4ZATsJo5nghk\n" + + "KYu63a0YQ5DRhUWEKk7CcMkrKnAUiZny\n-----END MEGOLM SESSION DATA-----" val expectedString = "Hello, World" var decodedString: String? = null @@ -123,7 +127,8 @@ class ExportEncryptionTest { @Test fun checkExportDecrypt3() { val password = "SWORDFISH" - val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXllc3NhbHR5Z29vZG5lc3P//////////wAAAAAAAAAAAAAD6OIW+Je7gwvjd4kYrb+49gKCfExw\n" + "MgJBMD4mrhLkmgAngwR1pHjbWXaoGybtiAYr0moQ93GrBQsCzPbvl82rZhaXO3iH5uHo/RCEpOqp\nPgg29363BGR+/Ripq/VCLKGNbw==\n-----END MEGOLM SESSION DATA-----" + val input = "-----BEGIN MEGOLM SESSION DATA-----\nAXllc3NhbHR5Z29vZG5lc3P//////////wAAAAAAAAAAAAAD6OIW+Je7gwvjd4kYrb+49gKCfExw\n" + + "MgJBMD4mrhLkmgAngwR1pHjbWXaoGybtiAYr0moQ93GrBQsCzPbvl82rZhaXO3iH5uHo/RCEpOqp\nPgg29363BGR+/Ripq/VCLKGNbw==\n-----END MEGOLM SESSION DATA-----" val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically" var decodedString: String? = null @@ -202,7 +207,8 @@ class ExportEncryptionTest { @Test fun checkExportEncrypt4() { - val password = "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" + val password = "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" + + "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" val expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically" var decodedString: String? = null diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt index 93aa78a3050a8cb6e48f5ca288d2d60626fade8c..e37ae5be86ffb8a2354a17aeb78244093c8f1d29 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/PreShareKeysTest.kt @@ -30,18 +30,14 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventCon import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.getTimelineEvent -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.JVM) class PreShareKeysTest : InstrumentedTest { - private val testHelper = CommonTestHelper(context()) - private val cryptoTestHelper = CryptoTestHelper(testHelper) - @Test - fun ensure_outbound_session_happy_path() { + fun ensure_outbound_session_happy_path() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val e2eRoomID = testData.roomId val aliceSession = testData.firstSession @@ -94,7 +90,5 @@ class PreShareKeysTest : InstrumentedTest { bobSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEvent.eventId)?.root?.getClearType() == EventType.MESSAGE } } - - testData.cleanUp(testHelper) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt index 0f3a4b4181923e7c032ef4dc96b076f2933e1bd2..e8a474a54a5d9cd60a9eef8e2be89194571768d1 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt @@ -21,6 +21,7 @@ import org.amshove.kluent.shouldBe import org.junit.Assert import org.junit.Before import org.junit.FixMethodOrder +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -38,8 +39,7 @@ import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm @@ -60,11 +60,10 @@ import kotlin.coroutines.resume */ @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.JVM) +@Ignore class UnwedgingTest : InstrumentedTest { private lateinit var messagesReceivedByBob: List<TimelineEvent> - private val testHelper = CommonTestHelper(context()) - private val cryptoTestHelper = CryptoTestHelper(testHelper) @Before fun init() { @@ -85,7 +84,7 @@ class UnwedgingTest : InstrumentedTest { * -> This is automatically fixed after SDKs restarted the olm session */ @Test - fun testUnwedging() { + fun testUnwedging() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val aliceSession = cryptoTestData.firstSession @@ -240,8 +239,6 @@ class UnwedgingTest : InstrumentedTest { } bobTimeline.dispose() - - cryptoTestData.cleanUp(testHelper) } private fun createEventListener(latch: CountDownLatch, expectedNumberOfMessages: Int): Timeline.Listener { diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt index a37626dc20b9bd7bc825def322e6e1287625fbb3..8cb38ddc8749d0bb6729374f8c7526718cae3749 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/crosssigning/XSigningTest.kt @@ -38,8 +38,8 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.isCrossSignedVerif import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.TestConstants import kotlin.coroutines.Continuation @@ -48,13 +48,11 @@ import kotlin.coroutines.resume @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @LargeTest +@Ignore class XSigningTest : InstrumentedTest { - private val testHelper = CommonTestHelper(context()) - private val cryptoTestHelper = CryptoTestHelper(testHelper) - @Test - fun test_InitializeAndStoreKeys() { + fun test_InitializeAndStoreKeys() = runSessionTest(context()) { testHelper -> val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) testHelper.doSync<Unit> { @@ -88,7 +86,7 @@ class XSigningTest : InstrumentedTest { } @Test - fun test_CrossSigningCheckBobSeesTheKeys() { + fun test_CrossSigningCheckBobSeesTheKeys() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val aliceSession = cryptoTestData.firstSession @@ -138,13 +136,10 @@ class XSigningTest : InstrumentedTest { ) assertFalse("Bob keys from alice pov should not be trusted", bobKeysFromAlicePOV.isTrusted()) - - cryptoTestData.cleanUp(testHelper) } @Test - @Ignore("This test will be ignored until it is fixed") - fun test_CrossSigningTestAliceTrustBobNewDevice() { + fun test_CrossSigningTestAliceTrustBobNewDevice() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val aliceSession = cryptoTestData.firstSession @@ -218,9 +213,5 @@ class XSigningTest : InstrumentedTest { val result = aliceSession.cryptoService().crossSigningService().checkDeviceTrust(bobUserId, bobSecondDeviceId, null) assertTrue("Bob second device should be trusted from alice POV", result.isCrossSignedVerified()) - - testHelper.signOutAndClose(aliceSession) - testHelper.signOutAndClose(bobSession) - testHelper.signOutAndClose(bobSession2) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt index 85b6c21df37ea2744e84c86b29cbe9a8c89f036d..5f26fda94618019f119284305fa27a2360fbf50a 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/encryption/EncryptionTest.kt @@ -35,6 +35,7 @@ import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest import org.matrix.android.sdk.common.CryptoTestHelper import java.util.concurrent.CountDownLatch @@ -42,35 +43,36 @@ import java.util.concurrent.CountDownLatch @FixMethodOrder(MethodSorters.NAME_ASCENDING) class EncryptionTest : InstrumentedTest { - private val testHelper = CommonTestHelper(context()) - private val cryptoTestHelper = CryptoTestHelper(testHelper) - @Test fun test_EncryptionEvent() { - performTest(roomShouldBeEncrypted = false) { room -> - // Send an encryption Event as an Event (and not as a state event) - room.sendService().sendEvent( - eventType = EventType.STATE_ROOM_ENCRYPTION, - content = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent() - ) + runCryptoTest(context()) { cryptoTestHelper, testHelper -> + performTest(cryptoTestHelper, testHelper, roomShouldBeEncrypted = false) { room -> + // Send an encryption Event as an Event (and not as a state event) + room.sendService().sendEvent( + eventType = EventType.STATE_ROOM_ENCRYPTION, + content = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent() + ) + } } } @Test fun test_EncryptionStateEvent() { - performTest(roomShouldBeEncrypted = true) { room -> - runBlocking { - // Send an encryption Event as a State Event - room.stateService().sendStateEvent( - eventType = EventType.STATE_ROOM_ENCRYPTION, - stateKey = "", - body = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent() - ) + runCryptoTest(context()) { cryptoTestHelper, testHelper -> + performTest(cryptoTestHelper, testHelper, roomShouldBeEncrypted = true) { room -> + runBlocking { + // Send an encryption Event as a State Event + room.stateService().sendStateEvent( + eventType = EventType.STATE_ROOM_ENCRYPTION, + stateKey = "", + body = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent() + ) + } } } } - private fun performTest(roomShouldBeEncrypted: Boolean, action: (Room) -> Unit) { + private fun performTest(cryptoTestHelper: CryptoTestHelper, testHelper: CommonTestHelper, roomShouldBeEncrypted: Boolean, action: (Room) -> Unit) { val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(encryptedRoom = false) val aliceSession = cryptoTestData.firstSession @@ -109,6 +111,5 @@ class EncryptionTest : InstrumentedTest { room.roomCryptoService().isEncrypted() shouldBe roomShouldBeEncrypted it.countDown() } - cryptoTestData.cleanUp(testHelper) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt index 2e4fd62822ba37ca2c43ba3cc9c17497e2f18817..7bb53e139c3bd5d63206c844f0fa57aeb51755a2 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/KeyShareTests.kt @@ -21,11 +21,12 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.LargeTest import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.assertTrue -import junit.framework.TestCase.fail import org.amshove.kluent.internal.assertEquals import org.junit.Assert import org.junit.Assert.assertNull import org.junit.FixMethodOrder +import org.junit.Ignore +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -41,20 +42,22 @@ import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest +import org.matrix.android.sdk.common.RetryTestRule import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.TestConstants +import org.matrix.android.sdk.mustFail @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.JVM) @LargeTest +@Ignore class KeyShareTests : InstrumentedTest { + @get:Rule val rule = RetryTestRule(3) + @Test - fun test_DoNotSelfShareIfNotTrusted() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + fun test_DoNotSelfShareIfNotTrusted() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val aliceSession = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) Log.v("TEST", "=======> AliceSession 1 is ${aliceSession.sessionParams.deviceId}") @@ -91,12 +94,10 @@ class KeyShareTests : InstrumentedTest { assertNotNull(receivedEvent) assert(receivedEvent!!.isEncrypted()) - try { - commonTestHelper.runBlockingTest { + commonTestHelper.runBlockingTest { + mustFail { aliceSession2.cryptoService().decryptEvent(receivedEvent.root, "foo") } - fail("should fail") - } catch (failure: Throwable) { } val outgoingRequestsBefore = aliceSession2.cryptoService().getOutgoingRoomKeyRequests() @@ -164,12 +165,10 @@ class KeyShareTests : InstrumentedTest { } } - try { - commonTestHelper.runBlockingTest { + commonTestHelper.runBlockingTest { + mustFail { aliceSession2.cryptoService().decryptEvent(receivedEvent.root, "foo") } - fail("should fail") - } catch (failure: Throwable) { } // Mark the device as trusted @@ -194,9 +193,7 @@ class KeyShareTests : InstrumentedTest { * if the key was originally shared with him */ @Test - fun test_reShareIfWasIntendedToBeShared() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + fun test_reShareIfWasIntendedToBeShared() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val aliceSession = testData.firstSession @@ -227,9 +224,7 @@ class KeyShareTests : InstrumentedTest { * if the key was originally shared with him */ @Test - fun test_reShareToUnverifiedIfWasIntendedToBeShared() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + fun test_reShareToUnverifiedIfWasIntendedToBeShared() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val testData = cryptoTestHelper.doE2ETestWithAliceInARoom(true) val aliceSession = testData.firstSession @@ -266,9 +261,7 @@ class KeyShareTests : InstrumentedTest { * Tests that keys reshared with own verified session are done from the earliest known index */ @Test - fun test_reShareFromTheEarliestKnownIndexWithOwnVerifiedSession() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + fun test_reShareFromTheEarliestKnownIndexWithOwnVerifiedSession() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val aliceSession = testData.firstSession @@ -388,10 +381,7 @@ class KeyShareTests : InstrumentedTest { * Tests that we don't cancel a request to early on first forward if the index is not good enough */ @Test - fun test_dontCancelToEarly() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) - + fun test_dontCancelToEarly() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) val aliceSession = testData.firstSession val bobSession = testData.secondSession!! @@ -434,7 +424,7 @@ class KeyShareTests : InstrumentedTest { // /!\ Stop initial alice session syncing so that it can't reply aliceSession.cryptoService().enableKeyGossiping(false) - aliceSession.stopSync() + aliceSession.syncService().stopSync() // Let's now try to request aliceNewSession.cryptoService().reRequestRoomKeyForEvent(sentEvents.first().root) @@ -442,7 +432,7 @@ class KeyShareTests : InstrumentedTest { // Should get a reply from bob and not from alice commonTestHelper.waitWithLatch { latch -> commonTestHelper.retryPeriodicallyWithLatch(latch) { - // Log.d("#TEST", "outgoing key requests :${aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().joinToString { it.sessionId ?: "?" }}") + // Log.d("#TEST", "outgoing key requests :${aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().joinToString { it.sessionId ?: "?" }}") val outgoing = aliceNewSession.cryptoService().getOutgoingRoomKeyRequests().firstOrNull { it.sessionId == sentEventMegolmSession } val bobReply = outgoing?.results?.firstOrNull { it.userId == bobSession.myUserId } val result = bobReply?.result @@ -457,7 +447,7 @@ class KeyShareTests : InstrumentedTest { // let's wake up alice aliceSession.cryptoService().enableKeyGossiping(true) - aliceSession.startSync(true) + aliceSession.syncService().startSync(true) // We should now get a reply from first session commonTestHelper.waitWithLatch { latch -> diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt index cb31a2232fb672c7e54fecbfff1a5c5c91e90d9e..ae420a09b38e59414d3cc90dd223a62369cafc22 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/gossiping/WithHeldTests.kt @@ -21,6 +21,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.LargeTest import org.junit.Assert import org.junit.FixMethodOrder +import org.junit.Ignore +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -35,21 +37,23 @@ import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.getTimelineEvent -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest import org.matrix.android.sdk.common.MockOkHttpInterceptor +import org.matrix.android.sdk.common.RetryTestRule import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.TestConstants +import org.matrix.android.sdk.mustFail @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.JVM) @LargeTest +@Ignore class WithHeldTests : InstrumentedTest { + @get:Rule val rule = RetryTestRule(3) + @Test - fun test_WithHeldUnverifiedReason() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun test_WithHeldUnverifiedReason() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> // ============================= // ARRANGE @@ -92,17 +96,19 @@ class WithHeldTests : InstrumentedTest { // ============================= // Bob should not be able to decrypt because the keys is withheld - try { - // .. might need to wait a bit for stability? - testHelper.runBlockingTest { + // .. might need to wait a bit for stability? + testHelper.runBlockingTest { + mustFail( + message = "This session should not be able to decrypt", + failureBlock = { failure -> + val type = (failure as MXCryptoError.Base).errorType + val technicalMessage = failure.technicalMessage + Assert.assertEquals("Error should be withheld", MXCryptoError.ErrorType.KEYS_WITHHELD, type) + Assert.assertEquals("Cause should be unverified", WithHeldCode.UNVERIFIED.value, technicalMessage) + } + ) { bobUnverifiedSession.cryptoService().decryptEvent(eventBobPOV.root, "") } - Assert.fail("This session should not be able to decrypt") - } catch (failure: Throwable) { - val type = (failure as MXCryptoError.Base).errorType - val technicalMessage = failure.technicalMessage - Assert.assertEquals("Error should be withheld", MXCryptoError.ErrorType.KEYS_WITHHELD, type) - Assert.assertEquals("Cause should be unverified", WithHeldCode.UNAUTHORISED.value, technicalMessage) } // Let's see if the reply we got from bob first session is unverified @@ -133,28 +139,23 @@ class WithHeldTests : InstrumentedTest { } // Previous message should still be undecryptable (partially withheld session) - try { - // .. might need to wait a bit for stability? - testHelper.runBlockingTest { + // .. might need to wait a bit for stability? + testHelper.runBlockingTest { + mustFail( + message = "This session should not be able to decrypt", + failureBlock = { failure -> + val type = (failure as MXCryptoError.Base).errorType + val technicalMessage = failure.technicalMessage + Assert.assertEquals("Error should be withheld", MXCryptoError.ErrorType.KEYS_WITHHELD, type) + Assert.assertEquals("Cause should be unverified", WithHeldCode.UNVERIFIED.value, technicalMessage) + }) { bobUnverifiedSession.cryptoService().decryptEvent(eventBobPOV.root, "") } - Assert.fail("This session should not be able to decrypt") - } catch (failure: Throwable) { - val type = (failure as MXCryptoError.Base).errorType - val technicalMessage = failure.technicalMessage - Assert.assertEquals("Error should be withheld", MXCryptoError.ErrorType.KEYS_WITHHELD, type) - Assert.assertEquals("Cause should be unverified", WithHeldCode.UNAUTHORISED.value, technicalMessage) } - - testHelper.signOutAndClose(aliceSession) - testHelper.signOutAndClose(bobSession) - testHelper.signOutAndClose(bobUnverifiedSession) } @Test - fun test_WithHeldNoOlm() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun test_WithHeldNoOlm() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val aliceSession = testData.firstSession @@ -186,17 +187,18 @@ class WithHeldTests : InstrumentedTest { // Previous message should still be undecryptable (partially withheld session) val eventBobPOV = bobSession.getRoom(testData.roomId)?.getTimelineEvent(eventId) - try { - // .. might need to wait a bit for stability? - testHelper.runBlockingTest { + // .. might need to wait a bit for stability? + testHelper.runBlockingTest { + mustFail( + message = "This session should not be able to decrypt", + failureBlock = { failure -> + val type = (failure as MXCryptoError.Base).errorType + val technicalMessage = failure.technicalMessage + Assert.assertEquals("Error should be withheld", MXCryptoError.ErrorType.KEYS_WITHHELD, type) + Assert.assertEquals("Cause should be unverified", WithHeldCode.NO_OLM.value, technicalMessage) + }) { bobSession.cryptoService().decryptEvent(eventBobPOV!!.root, "") } - Assert.fail("This session should not be able to decrypt") - } catch (failure: Throwable) { - val type = (failure as MXCryptoError.Base).errorType - val technicalMessage = failure.technicalMessage - Assert.assertEquals("Error should be withheld", MXCryptoError.ErrorType.KEYS_WITHHELD, type) - Assert.assertEquals("Cause should be unverified", WithHeldCode.NO_OLM.value, technicalMessage) } // Ensure that alice has marked the session to be shared with bob @@ -230,14 +232,10 @@ class WithHeldTests : InstrumentedTest { Assert.assertEquals("Alice should have marked bob's device for this session", 1, chainIndex2) aliceInterceptor.clearRules() - testData.cleanUp(testHelper) - testHelper.signOutAndClose(bobSecondSession) } @Test - fun test_WithHeldKeyRequest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun test_WithHeldKeyRequest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val aliceSession = testData.firstSession @@ -284,8 +282,5 @@ class WithHeldTests : InstrumentedTest { wc?.code == WithHeldCode.UNAUTHORISED } } - - testHelper.signOutAndClose(aliceSession) - testHelper.signOutAndClose(bobSecondSession) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt index 9136272b1ee7fc396c7a162e797efe1c75a5d72d..fb498e0de5dfde0e47a872738d7ea5fe32b7b111 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt @@ -24,6 +24,8 @@ import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.FixMethodOrder +import org.junit.Ignore +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -43,8 +45,9 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreation import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult import org.matrix.android.sdk.api.session.getRoom -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest +import org.matrix.android.sdk.common.RetryTestRule import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.common.TestMatrixCallback import java.util.Collections @@ -53,17 +56,18 @@ import java.util.concurrent.CountDownLatch @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.JVM) @LargeTest +@Ignore class KeysBackupTest : InstrumentedTest { + @get:Rule val rule = RetryTestRule(3) + /** * - From doE2ETestWithAliceAndBobInARoomWithEncryptedMessages, we should have no backed up keys * - Check backup keys after having marked one as backed up * - Reset keys backup markers */ @Test - fun roomKeysTest_testBackupStore_ok() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun roomKeysTest_testBackupStore_ok() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages() @@ -102,8 +106,7 @@ class KeysBackupTest : InstrumentedTest { * Check that prepareKeysBackupVersionWithPassword returns valid data */ @Test - fun prepareKeysBackupVersionTest() { - val testHelper = CommonTestHelper(context()) + fun prepareKeysBackupVersionTest() = runSessionTest(context()) { testHelper -> val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams) @@ -113,7 +116,7 @@ class KeysBackupTest : InstrumentedTest { val stateObserver = StateObserver(keysBackup) - assertFalse(keysBackup.isEnabled) + assertFalse(keysBackup.isEnabled()) val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> { keysBackup.prepareKeysBackupVersion(null, null, it) @@ -125,16 +128,13 @@ class KeysBackupTest : InstrumentedTest { assertNotNull(megolmBackupCreationInfo.recoveryKey) stateObserver.stopAndCheckStates(null) - testHelper.signOutAndClose(bobSession) } /** * Test creating a keys backup version and check that createKeysBackupVersion() returns valid data */ @Test - fun createKeysBackupVersionTest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun createKeysBackupVersionTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams) cryptoTestHelper.initializeCrossSigning(bobSession) @@ -143,13 +143,13 @@ class KeysBackupTest : InstrumentedTest { val stateObserver = StateObserver(keysBackup) - assertFalse(keysBackup.isEnabled) + assertFalse(keysBackup.isEnabled()) val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> { keysBackup.prepareKeysBackupVersion(null, null, it) } - assertFalse(keysBackup.isEnabled) + assertFalse(keysBackup.isEnabled()) // Create the version val version = testHelper.doSync<KeysVersion> { @@ -157,7 +157,7 @@ class KeysBackupTest : InstrumentedTest { } // Backup must be enable now - assertTrue(keysBackup.isEnabled) + assertTrue(keysBackup.isEnabled()) // Check that it's signed with MSK val versionResult = testHelper.doSync<KeysVersionResult?> { @@ -193,7 +193,6 @@ class KeysBackupTest : InstrumentedTest { } stateObserver.stopAndCheckStates(null) - testHelper.signOutAndClose(bobSession) } /** @@ -201,9 +200,7 @@ class KeysBackupTest : InstrumentedTest { * - Check the backup completes */ @Test - fun backupAfterCreateKeysBackupVersionTest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun backupAfterCreateKeysBackupVersionTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages() @@ -238,16 +235,13 @@ class KeysBackupTest : InstrumentedTest { KeysBackupState.ReadyToBackUp ) ) - cryptoTestData.cleanUp(testHelper) } /** * Check that backupAllGroupSessions() returns valid data */ @Test - fun backupAllGroupSessionsTest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun backupAllGroupSessionsTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages() @@ -281,7 +275,6 @@ class KeysBackupTest : InstrumentedTest { assertEquals("All keys must have been marked as backed up", nbOfKeys, backedUpKeys) stateObserver.stopAndCheckStates(null) - cryptoTestData.cleanUp(testHelper) } /** @@ -293,9 +286,7 @@ class KeysBackupTest : InstrumentedTest { * - Compare the decrypted megolm key with the original one */ @Test - fun testEncryptAndDecryptKeysBackupData() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun testEncryptAndDecryptKeysBackupData() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoomWithEncryptedMessages() @@ -330,7 +321,6 @@ class KeysBackupTest : InstrumentedTest { keysBackupTestHelper.assertKeysEquals(session.exportKeys(), sessionData) stateObserver.stopAndCheckStates(null) - cryptoTestData.cleanUp(testHelper) } /** @@ -340,9 +330,7 @@ class KeysBackupTest : InstrumentedTest { * - Restore must be successful */ @Test - fun restoreKeysBackupTest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun restoreKeysBackupTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null) @@ -428,9 +416,7 @@ class KeysBackupTest : InstrumentedTest { * - It must be trusted and must have with 2 signatures now */ @Test - fun trustKeyBackupVersionTest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun trustKeyBackupVersionTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) // - Do an e2e backup to the homeserver with a recovery key @@ -441,8 +427,8 @@ class KeysBackupTest : InstrumentedTest { // - The new device must see the previous backup as not trusted assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) - assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) - assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) + assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled()) + assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState()) // - Trust the backup from the new device testHelper.doSync<Unit> { @@ -458,7 +444,7 @@ class KeysBackupTest : InstrumentedTest { // - Backup must be enabled on the new device, on the same version assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version) - assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) + assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled()) // - Retrieve the last version from the server val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> { @@ -477,7 +463,6 @@ class KeysBackupTest : InstrumentedTest { assertEquals(2, keysBackupVersionTrust.signatures.size) stateObserver.stopAndCheckStates(null) - testData.cleanUp(testHelper) } /** @@ -491,9 +476,7 @@ class KeysBackupTest : InstrumentedTest { * - It must be trusted and must have with 2 signatures now */ @Test - fun trustKeyBackupVersionWithRecoveryKeyTest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun trustKeyBackupVersionWithRecoveryKeyTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) // - Do an e2e backup to the homeserver with a recovery key @@ -504,8 +487,8 @@ class KeysBackupTest : InstrumentedTest { // - The new device must see the previous backup as not trusted assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) - assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) - assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) + assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled()) + assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState()) // - Trust the backup from the new device with the recovery key testHelper.doSync<Unit> { @@ -521,7 +504,7 @@ class KeysBackupTest : InstrumentedTest { // - Backup must be enabled on the new device, on the same version assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version) - assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) + assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled()) // - Retrieve the last version from the server val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> { @@ -540,7 +523,6 @@ class KeysBackupTest : InstrumentedTest { assertEquals(2, keysBackupVersionTrust.signatures.size) stateObserver.stopAndCheckStates(null) - testData.cleanUp(testHelper) } /** @@ -552,9 +534,7 @@ class KeysBackupTest : InstrumentedTest { * - The backup must still be untrusted and disabled */ @Test - fun trustKeyBackupVersionWithWrongRecoveryKeyTest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun trustKeyBackupVersionWithWrongRecoveryKeyTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) // - Do an e2e backup to the homeserver with a recovery key @@ -565,8 +545,8 @@ class KeysBackupTest : InstrumentedTest { // - The new device must see the previous backup as not trusted assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) - assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) - assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) + assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled()) + assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState()) // - Try to trust the backup from the new device with a wrong recovery key val latch = CountDownLatch(1) @@ -579,11 +559,10 @@ class KeysBackupTest : InstrumentedTest { // - The new device must still see the previous backup as not trusted assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) - assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) - assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) + assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled()) + assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState()) stateObserver.stopAndCheckStates(null) - testData.cleanUp(testHelper) } /** @@ -597,9 +576,7 @@ class KeysBackupTest : InstrumentedTest { * - It must be trusted and must have with 2 signatures now */ @Test - fun trustKeyBackupVersionWithPasswordTest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun trustKeyBackupVersionWithPasswordTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val password = "Password" @@ -612,8 +589,8 @@ class KeysBackupTest : InstrumentedTest { // - The new device must see the previous backup as not trusted assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) - assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) - assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) + assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled()) + assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState()) // - Trust the backup from the new device with the password testHelper.doSync<Unit> { @@ -629,7 +606,7 @@ class KeysBackupTest : InstrumentedTest { // - Backup must be enabled on the new device, on the same version assertEquals(testData.prepareKeysBackupDataResult.version, testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion?.version) - assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) + assertTrue(testData.aliceSession2.cryptoService().keysBackupService().isEnabled()) // - Retrieve the last version from the server val keysVersionResult = testHelper.doSync<KeysBackupLastVersionResult> { @@ -648,7 +625,6 @@ class KeysBackupTest : InstrumentedTest { assertEquals(2, keysBackupVersionTrust.signatures.size) stateObserver.stopAndCheckStates(null) - testData.cleanUp(testHelper) } /** @@ -660,9 +636,7 @@ class KeysBackupTest : InstrumentedTest { * - The backup must still be untrusted and disabled */ @Test - fun trustKeyBackupVersionWithWrongPasswordTest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun trustKeyBackupVersionWithWrongPasswordTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val password = "Password" @@ -676,8 +650,8 @@ class KeysBackupTest : InstrumentedTest { // - The new device must see the previous backup as not trusted assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) - assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) - assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) + assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled()) + assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState()) // - Try to trust the backup from the new device with a wrong password val latch = CountDownLatch(1) @@ -690,11 +664,10 @@ class KeysBackupTest : InstrumentedTest { // - The new device must still see the previous backup as not trusted assertNotNull(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion) - assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled) - assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().state) + assertFalse(testData.aliceSession2.cryptoService().keysBackupService().isEnabled()) + assertEquals(KeysBackupState.NotTrusted, testData.aliceSession2.cryptoService().keysBackupService().getState()) stateObserver.stopAndCheckStates(null) - testData.cleanUp(testHelper) } /** @@ -704,9 +677,7 @@ class KeysBackupTest : InstrumentedTest { * - It must fail */ @Test - fun restoreKeysBackupWithAWrongRecoveryKeyTest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun restoreKeysBackupWithAWrongRecoveryKeyTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null) @@ -730,8 +701,6 @@ class KeysBackupTest : InstrumentedTest { // onSuccess may not have been called assertNull(importRoomKeysResult) - - testData.cleanUp(testHelper) } /** @@ -741,9 +710,7 @@ class KeysBackupTest : InstrumentedTest { * - Restore must be successful */ @Test - fun testBackupWithPassword() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun testBackupWithPassword() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val password = "password" @@ -790,8 +757,6 @@ class KeysBackupTest : InstrumentedTest { assertEquals(100, (steps[104] as StepProgressListener.Step.ImportingKey).progress) keysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys) - - testData.cleanUp(testHelper) } /** @@ -801,9 +766,7 @@ class KeysBackupTest : InstrumentedTest { * - It must fail */ @Test - fun restoreKeysBackupWithAWrongPasswordTest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun restoreKeysBackupWithAWrongPasswordTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val password = "password" @@ -830,8 +793,6 @@ class KeysBackupTest : InstrumentedTest { // onSuccess may not have been called assertNull(importRoomKeysResult) - - testData.cleanUp(testHelper) } /** @@ -841,9 +802,7 @@ class KeysBackupTest : InstrumentedTest { * - Restore must be successful */ @Test - fun testUseRecoveryKeyToRestoreAPasswordBasedKeysBackup() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun testUseRecoveryKeyToRestoreAPasswordBasedKeysBackup() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val password = "password" @@ -863,8 +822,6 @@ class KeysBackupTest : InstrumentedTest { } keysBackupTestHelper.checkRestoreSuccess(testData, importRoomKeysResult.totalNumberOfKeys, importRoomKeysResult.successfullyNumberOfImportedKeys) - - testData.cleanUp(testHelper) } /** @@ -874,9 +831,7 @@ class KeysBackupTest : InstrumentedTest { * - It must fail */ @Test - fun testUsePasswordToRestoreARecoveryKeyBasedKeysBackup() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun testUsePasswordToRestoreARecoveryKeyBasedKeysBackup() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(null) @@ -900,8 +855,6 @@ class KeysBackupTest : InstrumentedTest { // onSuccess may not have been called assertNull(importRoomKeysResult) - - testData.cleanUp(testHelper) } /** @@ -909,9 +862,7 @@ class KeysBackupTest : InstrumentedTest { * - Check the returned KeysVersionResult is trusted */ @Test - fun testIsKeysBackupTrusted() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun testIsKeysBackupTrusted() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) // - Create a backup version @@ -945,7 +896,6 @@ class KeysBackupTest : InstrumentedTest { assertEquals(signature.device!!.deviceId, cryptoTestData.firstSession.sessionParams.deviceId) stateObserver.stopAndCheckStates(null) - cryptoTestData.cleanUp(testHelper) } /** @@ -957,9 +907,7 @@ class KeysBackupTest : InstrumentedTest { * -> That must fail and her backup state must be WrongBackUpVersion */ @Test - fun testBackupWhenAnotherBackupWasCreated() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun testBackupWhenAnotherBackupWasCreated() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) // - Create a backup version @@ -969,7 +917,7 @@ class KeysBackupTest : InstrumentedTest { val stateObserver = StateObserver(keysBackup) - assertFalse(keysBackup.isEnabled) + assertFalse(keysBackup.isEnabled()) // Wait for keys backup to be finished val latch0 = CountDownLatch(1) @@ -993,7 +941,7 @@ class KeysBackupTest : InstrumentedTest { // - Make alice back up her keys to her homeserver keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup) - assertTrue(keysBackup.isEnabled) + assertTrue(keysBackup.isEnabled()) testHelper.await(latch0) @@ -1012,11 +960,10 @@ class KeysBackupTest : InstrumentedTest { testHelper.await(latch2) // -> That must fail and her backup state must be WrongBackUpVersion - assertEquals(KeysBackupState.WrongBackUpVersion, keysBackup.state) - assertFalse(keysBackup.isEnabled) + assertEquals(KeysBackupState.WrongBackUpVersion, keysBackup.getState()) + assertFalse(keysBackup.isEnabled()) stateObserver.stopAndCheckStates(null) - cryptoTestData.cleanUp(testHelper) } /** @@ -1032,9 +979,7 @@ class KeysBackupTest : InstrumentedTest { * -> It must success */ @Test - fun testBackupAfterVerifyingADevice() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun testBackupAfterVerifyingADevice() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) // - Create a backup version @@ -1069,7 +1014,7 @@ class KeysBackupTest : InstrumentedTest { // - Try to backup all in aliceSession2, it must fail val keysBackup2 = aliceSession2.cryptoService().keysBackupService() - assertFalse("Backup should not be enabled", keysBackup2.isEnabled) + assertFalse("Backup should not be enabled", keysBackup2.isEnabled()) val stateObserver2 = StateObserver(keysBackup2) @@ -1088,8 +1033,8 @@ class KeysBackupTest : InstrumentedTest { assertFalse(isSuccessful) // Backup state must be NotTrusted - assertEquals("Backup state must be NotTrusted", KeysBackupState.NotTrusted, keysBackup2.state) - assertFalse("Backup should not be enabled", keysBackup2.isEnabled) + assertEquals("Backup state must be NotTrusted", KeysBackupState.NotTrusted, keysBackup2.getState()) + assertFalse("Backup should not be enabled", keysBackup2.isEnabled()) // - Validate the old device from the new one aliceSession2.cryptoService().setDeviceVerification( @@ -1103,7 +1048,7 @@ class KeysBackupTest : InstrumentedTest { keysBackup2.addListener(object : KeysBackupStateListener { override fun onStateChange(newState: KeysBackupState) { // Check the backup completes - if (keysBackup2.state == KeysBackupState.ReadyToBackUp) { + if (keysBackup2.getState() == KeysBackupState.ReadyToBackUp) { // Remove itself from the list of listeners keysBackup2.removeListener(this) @@ -1121,12 +1066,10 @@ class KeysBackupTest : InstrumentedTest { } // -> It must success - assertTrue(aliceSession2.cryptoService().keysBackupService().isEnabled) + assertTrue(aliceSession2.cryptoService().keysBackupService().isEnabled()) stateObserver.stopAndCheckStates(null) stateObserver2.stopAndCheckStates(null) - testHelper.signOutAndClose(aliceSession2) - cryptoTestData.cleanUp(testHelper) } /** @@ -1134,9 +1077,7 @@ class KeysBackupTest : InstrumentedTest { * - Delete the backup */ @Test - fun deleteKeysBackupTest() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun deleteKeysBackupTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper) // - Create a backup version @@ -1146,19 +1087,18 @@ class KeysBackupTest : InstrumentedTest { val stateObserver = StateObserver(keysBackup) - assertFalse(keysBackup.isEnabled) + assertFalse(keysBackup.isEnabled()) val keyBackupCreationInfo = keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup) - assertTrue(keysBackup.isEnabled) + assertTrue(keysBackup.isEnabled()) // Delete the backup testHelper.doSync<Unit> { keysBackup.deleteBackup(keyBackupCreationInfo.version, it) } // Backup is now disabled - assertFalse(keysBackup.isEnabled) + assertFalse(keysBackup.isEnabled()) stateObserver.stopAndCheckStates(null) - cryptoTestData.cleanUp(testHelper) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt index 2220536e28c7579d8cf5af4367b425e2deb494a4..38f94c51039cb9a57c5af236c6f56233259b187a 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt @@ -33,7 +33,8 @@ import java.util.concurrent.CountDownLatch internal class KeysBackupTestHelper( private val testHelper: CommonTestHelper, - private val cryptoTestHelper: CryptoTestHelper) { + private val cryptoTestHelper: CryptoTestHelper +) { fun waitForKeybackUpBatching() { Thread.sleep(400) @@ -96,8 +97,10 @@ internal class KeysBackupTestHelper( ) } - fun prepareAndCreateKeysBackupData(keysBackup: KeysBackupService, - password: String? = null): PrepareKeysBackupDataResult { + fun prepareAndCreateKeysBackupData( + keysBackup: KeysBackupService, + password: String? = null + ): PrepareKeysBackupDataResult { val stateObserver = StateObserver(keysBackup) val megolmBackupCreationInfo = testHelper.doSync<MegolmBackupCreationInfo> { @@ -106,7 +109,7 @@ internal class KeysBackupTestHelper( Assert.assertNotNull(megolmBackupCreationInfo) - Assert.assertFalse("Key backup should not be enabled before creation", keysBackup.isEnabled) + Assert.assertFalse("Key backup should not be enabled before creation", keysBackup.isEnabled()) // Create the version val keysVersion = testHelper.doSync<KeysVersion> { @@ -116,7 +119,7 @@ internal class KeysBackupTestHelper( Assert.assertNotNull("Key backup version should not be null", keysVersion.version) // Backup must be enable now - Assert.assertTrue(keysBackup.isEnabled) + Assert.assertTrue(keysBackup.isEnabled()) stateObserver.stopAndCheckStates(null) return PrepareKeysBackupDataResult(megolmBackupCreationInfo, keysVersion.version) @@ -128,7 +131,7 @@ internal class KeysBackupTestHelper( */ fun waitForKeysBackupToBeInState(session: Session, state: KeysBackupState) { // If already in the wanted state, return - if (session.cryptoService().keysBackupService().state == state) { + if (session.cryptoService().keysBackupService().getState() == state) { return } @@ -169,9 +172,11 @@ internal class KeysBackupTestHelper( * - The new device must have the same count of megolm keys * - Alice must have the same keys on both devices */ - fun checkRestoreSuccess(testData: KeysBackupScenarioData, - total: Int, - imported: Int) { + fun checkRestoreSuccess( + testData: KeysBackupScenarioData, + total: Int, + imported: Int + ) { // - Imported keys number must be correct Assert.assertEquals(testData.aliceKeys.size, total) Assert.assertEquals(total, imported) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/PrepareKeysBackupDataResult.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/PrepareKeysBackupDataResult.kt index 31bd3c9cce5d8670f3db0ad745034a9e2493c263..9ee10eddcfc3bf3c21d46f79b571e85b737492d3 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/PrepareKeysBackupDataResult.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/PrepareKeysBackupDataResult.kt @@ -18,5 +18,7 @@ package org.matrix.android.sdk.internal.crypto.keysbackup import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo -data class PrepareKeysBackupDataResult(val megolmBackupCreationInfo: MegolmBackupCreationInfo, - val version: String) +data class PrepareKeysBackupDataResult( + val megolmBackupCreationInfo: MegolmBackupCreationInfo, + val version: String +) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/StateObserver.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/StateObserver.kt index 80e54d82ec76d115861c4ca5bdfa173281e85d29..6c977745479210a7b9c3f7f72965af86ea8da65c 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/StateObserver.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/StateObserver.kt @@ -27,9 +27,11 @@ import java.util.concurrent.CountDownLatch * This class observe the state change of a KeysBackup object and provide a method to check the several state change * It checks all state transitions and detected forbidden transition */ -internal class StateObserver(private val keysBackup: KeysBackupService, - private val latch: CountDownLatch? = null, - private val expectedStateChange: Int = -1) : KeysBackupStateListener { +internal class StateObserver( + private val keysBackup: KeysBackupService, + private val latch: CountDownLatch? = null, + private val expectedStateChange: Int = -1 +) : KeysBackupStateListener { private val allowedStateTransitions = listOf( KeysBackupState.BackingUp to KeysBackupState.ReadyToBackUp, diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/replayattack/ReplayAttackTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/replayattack/ReplayAttackTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..53cf802b91e9978a09906cff4fbc7e757db675fd --- /dev/null +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/replayattack/ReplayAttackTest.kt @@ -0,0 +1,109 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.crypto.replayattack + +import androidx.test.filters.LargeTest +import org.amshove.kluent.internal.assertFailsWith +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Assert.fail +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.runners.MethodSorters +import org.matrix.android.sdk.InstrumentedTest +import org.matrix.android.sdk.api.session.crypto.MXCryptoError +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest + +@RunWith(JUnit4::class) +@FixMethodOrder(MethodSorters.JVM) +@LargeTest +class ReplayAttackTest : InstrumentedTest { + + @Test + fun replayAttackAlreadyDecryptedEventTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> + val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) + + val e2eRoomID = cryptoTestData.roomId + + // Alice + val aliceSession = cryptoTestData.firstSession + val aliceRoomPOV = aliceSession.roomService().getRoom(e2eRoomID)!! + + // Bob + val bobSession = cryptoTestData.secondSession + val bobRoomPOV = bobSession!!.roomService().getRoom(e2eRoomID)!! + assertEquals(bobRoomPOV.roomSummary()?.joinedMembersCount, 2) + + // Alice will send a message + val sentEvents = testHelper.sendTextMessage(aliceRoomPOV, "Hello I will be decrypted twice", 1) + assertEquals(1, sentEvents.size) + + val fakeEventId = sentEvents[0].eventId + "_fake" + val fakeEventWithTheSameIndex = + sentEvents[0].copy(eventId = fakeEventId, root = sentEvents[0].root.copy(eventId = fakeEventId)) + + testHelper.runBlockingTest { + // Lets assume we are from the main timelineId + val timelineId = "timelineId" + // Lets decrypt the original event + aliceSession.cryptoService().decryptEvent(sentEvents[0].root, timelineId) + // Lets decrypt the fake event that will have the same message index + val exception = assertFailsWith<MXCryptoError.Base> { + // An exception should be thrown while the same index would have been used for the previous decryption + aliceSession.cryptoService().decryptEvent(fakeEventWithTheSameIndex.root, timelineId) + } + assertEquals(MXCryptoError.ErrorType.DUPLICATED_MESSAGE_INDEX, exception.errorType) + } + cryptoTestData.cleanUp(testHelper) + } + + @Test + fun replayAttackSameEventTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> + val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true) + + val e2eRoomID = cryptoTestData.roomId + + // Alice + val aliceSession = cryptoTestData.firstSession + val aliceRoomPOV = aliceSession.roomService().getRoom(e2eRoomID)!! + + // Bob + val bobSession = cryptoTestData.secondSession + val bobRoomPOV = bobSession!!.roomService().getRoom(e2eRoomID)!! + assertEquals(bobRoomPOV.roomSummary()?.joinedMembersCount, 2) + + // Alice will send a message + val sentEvents = testHelper.sendTextMessage(aliceRoomPOV, "Hello I will be decrypted twice", 1) + Assert.assertTrue("Message should be sent", sentEvents.size == 1) + assertEquals(sentEvents.size, 1) + + testHelper.runBlockingTest { + // Lets assume we are from the main timelineId + val timelineId = "timelineId" + // Lets decrypt the original event + aliceSession.cryptoService().decryptEvent(sentEvents[0].root, timelineId) + try { + // Lets try to decrypt the same event + aliceSession.cryptoService().decryptEvent(sentEvents[0].root, timelineId) + } catch (ex: Throwable) { + fail("Shouldn't throw a decryption error for same event") + } + } + } +} diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt index c758050fc9548f4a1fb926462e7ffb2e6c211279..c8be6aae74ec8a6bcb24a9a5ce4e36e238c591d7 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/ssss/QuadSTests.kt @@ -31,15 +31,16 @@ import org.matrix.android.sdk.api.crypto.SSSS_ALGORITHM_AES_HMAC_SHA2 import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent import org.matrix.android.sdk.api.session.securestorage.EncryptedSecretContent +import org.matrix.android.sdk.api.session.securestorage.KeyRef import org.matrix.android.sdk.api.session.securestorage.KeySigner import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec import org.matrix.android.sdk.api.session.securestorage.SecretStorageKeyContent import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageError -import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService import org.matrix.android.sdk.api.session.securestorage.SsssKeyCreationInfo import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toBase64NoPadding import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.TestConstants import org.matrix.android.sdk.internal.crypto.secrets.DefaultSharedSecretStorageService @@ -55,8 +56,7 @@ class QuadSTests : InstrumentedTest { } @Test - fun test_Generate4SKey() { - val testHelper = CommonTestHelper(context()) + fun test_Generate4SKey() = runSessionTest(context()) { testHelper -> val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) @@ -108,12 +108,11 @@ class QuadSTests : InstrumentedTest { } @Test - fun test_StoreSecret() { - val testHelper = CommonTestHelper(context()) + fun test_StoreSecret() = runSessionTest(context()) { testHelper -> val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) val keyId = "My.Key" - val info = generatedSecret(aliceSession, keyId, true) + val info = generatedSecret(testHelper, aliceSession, keyId, true) val keySpec = RawBytesKeySpec.fromRecoveryKey(info.recoveryKey) @@ -123,11 +122,11 @@ class QuadSTests : InstrumentedTest { aliceSession.sharedSecretStorageService().storeSecret( "secret.of.life", clearSecret, - listOf(SharedSecretStorageService.KeyRef(null, keySpec)) // default key + listOf(KeyRef(null, keySpec)) // default key ) } - val secretAccountData = assertAccountData(aliceSession, "secret.of.life") + val secretAccountData = assertAccountData(testHelper, aliceSession, "secret.of.life") val encryptedContent = secretAccountData.content["encrypted"] as? Map<*, *> assertNotNull("Element should be encrypted", encryptedContent) @@ -149,12 +148,10 @@ class QuadSTests : InstrumentedTest { } assertEquals("Secret mismatch", clearSecret, decryptedSecret) - testHelper.signOutAndClose(aliceSession) } @Test - fun test_SetDefaultLocalEcho() { - val testHelper = CommonTestHelper(context()) + fun test_SetDefaultLocalEcho() = runSessionTest(context()) { testHelper -> val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) @@ -170,19 +167,16 @@ class QuadSTests : InstrumentedTest { testHelper.runBlockingTest { quadS.setDefaultKey(TEST_KEY_ID) } - - testHelper.signOutAndClose(aliceSession) } @Test - fun test_StoreSecretWithMultipleKey() { - val testHelper = CommonTestHelper(context()) + fun test_StoreSecretWithMultipleKey() = runSessionTest(context()) { testHelper -> val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) val keyId1 = "Key.1" - val key1Info = generatedSecret(aliceSession, keyId1, true) + val key1Info = generatedSecret(testHelper, aliceSession, keyId1, true) val keyId2 = "Key2" - val key2Info = generatedSecret(aliceSession, keyId2, true) + val key2Info = generatedSecret(testHelper, aliceSession, keyId2, true) val mySecretText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit" @@ -191,8 +185,8 @@ class QuadSTests : InstrumentedTest { "my.secret", mySecretText.toByteArray().toBase64NoPadding(), listOf( - SharedSecretStorageService.KeyRef(keyId1, RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey)), - SharedSecretStorageService.KeyRef(keyId2, RawBytesKeySpec.fromRecoveryKey(key2Info.recoveryKey)) + KeyRef(keyId1, RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey)), + KeyRef(keyId2, RawBytesKeySpec.fromRecoveryKey(key2Info.recoveryKey)) ) ) } @@ -221,19 +215,16 @@ class QuadSTests : InstrumentedTest { RawBytesKeySpec.fromRecoveryKey(key2Info.recoveryKey)!! ) } - - testHelper.signOutAndClose(aliceSession) } @Test @Ignore("Test is working locally, not in GitHub actions") - fun test_GetSecretWithBadPassphrase() { - val testHelper = CommonTestHelper(context()) + fun test_GetSecretWithBadPassphrase() = runSessionTest(context()) { testHelper -> val aliceSession = testHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) val keyId1 = "Key.1" val passphrase = "The good pass phrase" - val key1Info = generatedSecretFromPassphrase(aliceSession, passphrase, keyId1, true) + val key1Info = generatedSecretFromPassphrase(testHelper, aliceSession, passphrase, keyId1, true) val mySecretText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit" @@ -241,7 +232,7 @@ class QuadSTests : InstrumentedTest { aliceSession.sharedSecretStorageService().storeSecret( "my.secret", mySecretText.toByteArray().toBase64NoPadding(), - listOf(SharedSecretStorageService.KeyRef(keyId1, RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey))) + listOf(KeyRef(keyId1, RawBytesKeySpec.fromRecoveryKey(key1Info.recoveryKey))) ) } @@ -275,13 +266,9 @@ class QuadSTests : InstrumentedTest { ) ) } - - testHelper.signOutAndClose(aliceSession) } - private fun assertAccountData(session: Session, type: String): UserAccountDataEvent { - val testHelper = CommonTestHelper(context()) - + private fun assertAccountData(testHelper: CommonTestHelper, session: Session, type: String): UserAccountDataEvent { var accountData: UserAccountDataEvent? = null testHelper.waitWithLatch { val liveAccountData = session.accountDataService().getLiveUserAccountDataEvent(type) @@ -297,29 +284,27 @@ class QuadSTests : InstrumentedTest { return accountData!! } - private fun generatedSecret(session: Session, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo { + private fun generatedSecret(testHelper: CommonTestHelper, session: Session, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo { val quadS = session.sharedSecretStorageService() - val testHelper = CommonTestHelper(context()) val creationInfo = testHelper.runBlockingTest { quadS.generateKey(keyId, null, keyId, emptyKeySigner) } - assertAccountData(session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId") + assertAccountData(testHelper, session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId") if (asDefault) { testHelper.runBlockingTest { quadS.setDefaultKey(keyId) } - assertAccountData(session, DefaultSharedSecretStorageService.DEFAULT_KEY_ID) + assertAccountData(testHelper, session, DefaultSharedSecretStorageService.DEFAULT_KEY_ID) } return creationInfo } - private fun generatedSecretFromPassphrase(session: Session, passphrase: String, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo { + private fun generatedSecretFromPassphrase(testHelper: CommonTestHelper, session: Session, passphrase: String, keyId: String, asDefault: Boolean = true): SsssKeyCreationInfo { val quadS = session.sharedSecretStorageService() - val testHelper = CommonTestHelper(context()) val creationInfo = testHelper.runBlockingTest { quadS.generateKeyWithPassphrase( @@ -331,12 +316,12 @@ class QuadSTests : InstrumentedTest { ) } - assertAccountData(session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId") + assertAccountData(testHelper, session, "${DefaultSharedSecretStorageService.KEY_ID_BASE}.$keyId") if (asDefault) { testHelper.runBlockingTest { quadS.setDefaultKey(keyId) } - assertAccountData(session, DefaultSharedSecretStorageService.DEFAULT_KEY_ID) + assertAccountData(testHelper, session, DefaultSharedSecretStorageService.DEFAULT_KEY_ID) } return creationInfo diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt index 2892cf846411d3dcaf273713d1184de254b02c57..c2e74abc59cd1729b821dc4bbc9d30f11a83f7e7 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/SASTest.kt @@ -44,8 +44,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransa import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toModel -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationCancel import org.matrix.android.sdk.internal.crypto.model.rest.KeyVerificationStart import org.matrix.android.sdk.internal.crypto.model.rest.toValue @@ -53,12 +52,11 @@ import java.util.concurrent.CountDownLatch @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Ignore class SASTest : InstrumentedTest { @Test - fun test_aliceStartThenAliceCancel() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun test_aliceStartThenAliceCancel() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val aliceSession = cryptoTestData.firstSession @@ -135,15 +133,11 @@ class SASTest : InstrumentedTest { assertNull(bobVerificationService.getExistingTransaction(aliceSession.myUserId, txID)) assertNull(aliceVerificationService.getExistingTransaction(bobSession.myUserId, txID)) - - cryptoTestData.cleanUp(testHelper) } @Test @Ignore("This test will be ignored until it is fixed") - fun test_key_agreement_protocols_must_include_curve25519() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun test_key_agreement_protocols_must_include_curve25519() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> fail("Not passing for the moment") val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() @@ -195,15 +189,11 @@ class SASTest : InstrumentedTest { testHelper.await(cancelLatch) assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod, cancelReason) - - cryptoTestData.cleanUp(testHelper) } @Test @Ignore("This test will be ignored until it is fixed") - fun test_key_agreement_macs_Must_include_hmac_sha256() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun test_key_agreement_macs_Must_include_hmac_sha256() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> fail("Not passing for the moment") val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() @@ -236,15 +226,11 @@ class SASTest : InstrumentedTest { val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!! assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code) - - cryptoTestData.cleanUp(testHelper) } @Test @Ignore("This test will be ignored until it is fixed") - fun test_key_agreement_short_code_include_decimal() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun test_key_agreement_short_code_include_decimal() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> fail("Not passing for the moment") val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() @@ -277,18 +263,18 @@ class SASTest : InstrumentedTest { val cancelReq = canceledToDeviceEvent!!.content.toModel<KeyVerificationCancel>()!! assertEquals("Request should be cancelled with m.unknown_method", CancelCode.UnknownMethod.value, cancelReq.code) - - cryptoTestData.cleanUp(testHelper) } - private fun fakeBobStart(bobSession: Session, - aliceUserID: String?, - aliceDevice: String?, - tid: String, - protocols: List<String> = SASDefaultVerificationTransaction.KNOWN_AGREEMENT_PROTOCOLS, - hashes: List<String> = SASDefaultVerificationTransaction.KNOWN_HASHES, - mac: List<String> = SASDefaultVerificationTransaction.KNOWN_MACS, - codes: List<String> = SASDefaultVerificationTransaction.KNOWN_SHORT_CODES) { + private fun fakeBobStart( + bobSession: Session, + aliceUserID: String?, + aliceDevice: String?, + tid: String, + protocols: List<String> = SASDefaultVerificationTransaction.KNOWN_AGREEMENT_PROTOCOLS, + hashes: List<String> = SASDefaultVerificationTransaction.KNOWN_HASHES, + mac: List<String> = SASDefaultVerificationTransaction.KNOWN_MACS, + codes: List<String> = SASDefaultVerificationTransaction.KNOWN_SHORT_CODES + ) { val startMessage = KeyVerificationStart( fromDevice = bobSession.cryptoService().getMyDevice().deviceId, method = VerificationMethod.SAS.toValue(), @@ -314,9 +300,7 @@ class SASTest : InstrumentedTest { // any two devices may only have at most one key verification in flight at a time. // If a device has two verifications in progress with the same device, then it should cancel both verifications. @Test - fun test_aliceStartTwoRequests() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun test_aliceStartTwoRequests() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val aliceSession = cryptoTestData.firstSession @@ -357,9 +341,7 @@ class SASTest : InstrumentedTest { */ @Test @Ignore("This test will be ignored until it is fixed") - fun test_aliceAndBobAgreement() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun test_aliceAndBobAgreement() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val aliceSession = cryptoTestData.firstSession @@ -413,14 +395,10 @@ class SASTest : InstrumentedTest { accepted!!.shortAuthenticationStrings.forEach { assertTrue("all agreed Short Code should be known by alice", startReq!!.shortAuthenticationStrings.contains(it)) } - - cryptoTestData.cleanUp(testHelper) } @Test - fun test_aliceAndBobSASCode() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun test_aliceAndBobSASCode() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val aliceSession = cryptoTestData.firstSession @@ -437,7 +415,7 @@ class SASTest : InstrumentedTest { OutgoingSasVerificationTransaction.UxState.SHOW_SAS -> { aliceSASLatch.countDown() } - else -> Unit + else -> Unit } } } @@ -451,7 +429,7 @@ class SASTest : InstrumentedTest { IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> { tx.performAccept() } - else -> Unit + else -> Unit } if (uxState === IncomingSasVerificationTransaction.UxState.SHOW_SAS) { bobSASLatch.countDown() @@ -473,14 +451,10 @@ class SASTest : InstrumentedTest { "Should have same SAS", aliceTx.getShortCodeRepresentation(SasMode.DECIMAL), bobTx.getShortCodeRepresentation(SasMode.DECIMAL) ) - - cryptoTestData.cleanUp(testHelper) } @Test - fun test_happyPath() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun test_happyPath() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val aliceSession = cryptoTestData.firstSession @@ -505,7 +479,7 @@ class SASTest : InstrumentedTest { aliceSASLatch.countDown() } } - else -> Unit + else -> Unit } } } @@ -525,16 +499,16 @@ class SASTest : InstrumentedTest { tx.performAccept() } } - IncomingSasVerificationTransaction.UxState.SHOW_SAS -> { + IncomingSasVerificationTransaction.UxState.SHOW_SAS -> { if (matchOnce) { matchOnce = false tx.userHasVerifiedShortCode() } } - IncomingSasVerificationTransaction.UxState.VERIFIED -> { + IncomingSasVerificationTransaction.UxState.VERIFIED -> { bobSASLatch.countDown() } - else -> Unit + else -> Unit } } } @@ -553,13 +527,10 @@ class SASTest : InstrumentedTest { assertTrue("alice device should be verified from bob point of view", aliceDeviceInfoFromBobPOV!!.isVerified) assertTrue("bob device should be verified from alice point of view", bobDeviceInfoFromAlicePOV!!.isVerified) - cryptoTestData.cleanUp(testHelper) } @Test - fun test_ConcurrentStart() { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + fun test_ConcurrentStart() = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val aliceSession = cryptoTestData.firstSession @@ -646,7 +617,5 @@ class SASTest : InstrumentedTest { bobPovTx?.state == VerificationTxState.ShortCodeReady } } - - cryptoTestData.cleanUp(testHelper) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/VerificationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/VerificationTest.kt index df3b2ffe276d2e982eb79963add0dcec97ad1d40..3f229069653067c43b4e0b13c1d5c95d72519994 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/VerificationTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/VerificationTest.kt @@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.crypto.verification.qrcode import androidx.test.ext.junit.runners.AndroidJUnit4 import org.amshove.kluent.shouldBe import org.junit.FixMethodOrder +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -27,11 +28,13 @@ import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserPasswordAuth import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse +import org.matrix.android.sdk.api.session.crypto.verification.CancelCode import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod import org.matrix.android.sdk.api.session.crypto.verification.VerificationService -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest +import org.matrix.android.sdk.common.SessionTestParams import org.matrix.android.sdk.common.TestConstants import java.util.concurrent.CountDownLatch import kotlin.coroutines.Continuation @@ -39,6 +42,7 @@ import kotlin.coroutines.resume @RunWith(AndroidJUnit4::class) @FixMethodOrder(MethodSorters.JVM) +@Ignore class VerificationTest : InstrumentedTest { data class ExpectedResult( @@ -149,12 +153,12 @@ class VerificationTest : InstrumentedTest { // TODO Add tests without SAS - private fun doTest(aliceSupportedMethods: List<VerificationMethod>, - bobSupportedMethods: List<VerificationMethod>, - expectedResultForAlice: ExpectedResult, - expectedResultForBob: ExpectedResult) { - val testHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(testHelper) + private fun doTest( + aliceSupportedMethods: List<VerificationMethod>, + bobSupportedMethods: List<VerificationMethod>, + expectedResultForAlice: ExpectedResult, + expectedResultForBob: ExpectedResult + ) = runCryptoTest(context()) { cryptoTestHelper, testHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() val aliceSession = cryptoTestData.firstSession @@ -249,7 +253,48 @@ class VerificationTest : InstrumentedTest { pr.otherCanShowQrCode() shouldBe expectedResultForBob.otherCanShowQrCode pr.otherCanScanQrCode() shouldBe expectedResultForBob.otherCanScanQrCode } + } + + @Test + fun test_selfVerificationAcceptedCancelsItForOtherSessions() = runSessionTest(context()) { testHelper -> + val defaultSessionParams = SessionTestParams(true) + + val aliceSessionToVerify = testHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams) + val aliceSessionThatVerifies = testHelper.logIntoAccount(aliceSessionToVerify.myUserId, TestConstants.PASSWORD, defaultSessionParams) + val aliceSessionThatReceivesCanceledEvent = testHelper.logIntoAccount(aliceSessionToVerify.myUserId, TestConstants.PASSWORD, defaultSessionParams) + + val verificationMethods = listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SCAN, VerificationMethod.QR_CODE_SHOW) + + val serviceOfVerified = aliceSessionToVerify.cryptoService().verificationService() + val serviceOfVerifier = aliceSessionThatVerifies.cryptoService().verificationService() + val serviceOfUserWhoReceivesCancellation = aliceSessionThatReceivesCanceledEvent.cryptoService().verificationService() + + serviceOfVerifier.addListener(object : VerificationService.Listener { + override fun verificationRequestCreated(pr: PendingVerificationRequest) { + // Accept verification request + serviceOfVerifier.readyPendingVerification( + verificationMethods, + pr.otherUserId, + pr.transactionId!!, + ) + } + }) + + serviceOfVerified.requestKeyVerification( + methods = verificationMethods, + otherUserId = aliceSessionToVerify.myUserId, + otherDevices = listOfNotNull(aliceSessionThatVerifies.sessionParams.deviceId, aliceSessionThatReceivesCanceledEvent.sessionParams.deviceId), + ) + + testHelper.waitWithLatch { latch -> + testHelper.retryPeriodicallyWithLatch(latch) { + val requests = serviceOfUserWhoReceivesCancellation.getExistingVerificationRequests(aliceSessionToVerify.myUserId) + requests.any { it.cancelConclusion == CancelCode.AcceptedByAnotherDevice } + } + } - cryptoTestData.cleanUp(testHelper) + testHelper.signOutAndClose(aliceSessionToVerify) + testHelper.signOutAndClose(aliceSessionThatVerifies) + testHelper.signOutAndClose(aliceSessionThatReceivesCanceledEvent) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt index acb23bf72382776d55b9f2f68eb352220417eaeb..0560cfec95f10f4e3e975b92c25565e89ee1d7e3 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt @@ -289,9 +289,11 @@ class MarkdownParserTest : InstrumentedTest { markdownParser.parse(text).expect(text, null) } - private fun testType(name: String, - markdownPattern: String, - htmlExpectedTag: String) { + private fun testType( + name: String, + markdownPattern: String, + htmlExpectedTag: String + ) { // Test simple case "$markdownPattern$name$markdownPattern" .let { @@ -376,10 +378,12 @@ class MarkdownParserTest : InstrumentedTest { } } - private fun testTypeNewLines(name: String, - markdownPattern: String, - htmlExpectedTag: String, - softBreak: String = "<br />") { + private fun testTypeNewLines( + name: String, + markdownPattern: String, + htmlExpectedTag: String, + softBreak: String = "<br />" + ) { // With new line inside the block "$markdownPattern$name\n$name$markdownPattern" .let { diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/TestPermalinkService.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/TestPermalinkService.kt index 2f9a5e0a73a656f0f00dfdf048fafd85b5e252d2..3a267ec694bec4ecd0346faf24acb62fbf223ada 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/TestPermalinkService.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/TestPermalinkService.kt @@ -44,7 +44,7 @@ class TestPermalinkService : PermalinkService { override fun createMentionSpanTemplate(type: PermalinkService.SpanTemplateType, forceMatrixTo: Boolean): String { return when (type) { - HTML -> "<a href=\"https://matrix.to/#/%1\$s\">%2\$s</a>" + HTML -> "<a href=\"https://matrix.to/#/%1\$s\">%2\$s</a>" MARKDOWN -> "[%2\$s](https://matrix.to/#/%1\$s)" } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt index a2984dd27e2de8d27d082e5df6579049a8f3e456..45bd38870d3921c2b09a7c74353a807c9b88dcc1 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/threads/ThreadMessagingTest.kt @@ -34,8 +34,7 @@ import org.matrix.android.sdk.api.session.events.model.isThread import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest import java.util.concurrent.CountDownLatch @RunWith(JUnit4::class) @@ -44,9 +43,7 @@ import java.util.concurrent.CountDownLatch class ThreadMessagingTest : InstrumentedTest { @Test - fun reply_in_thread_should_create_a_thread() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + fun reply_in_thread_should_create_a_thread() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(false) val aliceSession = cryptoTestData.firstSession @@ -86,7 +83,7 @@ class ThreadMessagingTest : InstrumentedTest { val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30)) timeline.start() - aliceSession.startSync(true) + aliceSession.syncService().startSync(true) run { val lock = CountDownLatch(1) val eventsListener = commonTestHelper.createEventListener(lock) { snapshot -> @@ -100,13 +97,11 @@ class ThreadMessagingTest : InstrumentedTest { timeline.addListener(eventsListener) commonTestHelper.await(lock, 600_000) } - aliceSession.stopSync() + aliceSession.syncService().stopSync() } @Test - fun reply_in_thread_should_create_a_thread_from_other_user() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + fun reply_in_thread_should_create_a_thread_from_other_user() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false) val aliceSession = cryptoTestData.firstSession @@ -149,7 +144,7 @@ class ThreadMessagingTest : InstrumentedTest { val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30)) timeline.start() - aliceSession.startSync(true) + aliceSession.syncService().startSync(true) run { val lock = CountDownLatch(1) val eventsListener = commonTestHelper.createEventListener(lock) { snapshot -> @@ -161,9 +156,9 @@ class ThreadMessagingTest : InstrumentedTest { timeline.addListener(eventsListener) commonTestHelper.await(lock, 600_000) } - aliceSession.stopSync() + aliceSession.syncService().stopSync() - bobSession.startSync(true) + bobSession.syncService().startSync(true) run { val lock = CountDownLatch(1) val eventsListener = commonTestHelper.createEventListener(lock) { snapshot -> @@ -175,13 +170,11 @@ class ThreadMessagingTest : InstrumentedTest { timeline.addListener(eventsListener) commonTestHelper.await(lock, 600_000) } - bobSession.stopSync() + bobSession.syncService().stopSync() } @Test - fun reply_in_thread_to_timeline_message_multiple_times() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + fun reply_in_thread_to_timeline_message_multiple_times() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(false) val aliceSession = cryptoTestData.firstSession @@ -224,7 +217,7 @@ class ThreadMessagingTest : InstrumentedTest { val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30)) timeline.start() - aliceSession.startSync(true) + aliceSession.syncService().startSync(true) run { val lock = CountDownLatch(1) val eventsListener = commonTestHelper.createEventListener(lock) { snapshot -> @@ -240,13 +233,11 @@ class ThreadMessagingTest : InstrumentedTest { timeline.addListener(eventsListener) commonTestHelper.await(lock, 600_000) } - aliceSession.stopSync() + aliceSession.syncService().stopSync() } @Test - fun thread_summary_advanced_validation_after_multiple_messages_in_multiple_threads() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + fun thread_summary_advanced_validation_after_multiple_messages_in_multiple_threads() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false) val aliceSession = cryptoTestData.firstSession @@ -323,7 +314,7 @@ class ThreadMessagingTest : InstrumentedTest { val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30)) timeline.start() - aliceSession.startSync(true) + aliceSession.syncService().startSync(true) run { val lock = CountDownLatch(1) val eventsListener = commonTestHelper.createEventListener(lock) { snapshot -> @@ -347,6 +338,6 @@ class ThreadMessagingTest : InstrumentedTest { timeline.addListener(eventsListener) commonTestHelper.await(lock, 600_000) } - aliceSession.stopSync() + aliceSession.syncService().stopSync() } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt index 94b2ba55a3456bdbacd1e47958b96a55b6a0bd0f..7b0d57abbcfa117b66166e8ef66edadfaca7e7c9 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/ChunkEntityTest.kt @@ -22,7 +22,6 @@ import io.realm.Realm import io.realm.RealmConfiguration import io.realm.kotlin.createObject import org.amshove.kluent.shouldBeEqualTo -import org.amshove.kluent.shouldBeTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -30,13 +29,11 @@ import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.internal.database.helper.addTimelineEvent -import org.matrix.android.sdk.internal.database.helper.merge import org.matrix.android.sdk.internal.database.mapper.toEntity import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.SessionRealmModule import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection import org.matrix.android.sdk.internal.util.time.DefaultClock -import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeListOfEvents import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeMessageEvent @RunWith(AndroidJUnit4::class) @@ -97,66 +94,11 @@ internal class ChunkEntityTest : InstrumentedTest { } } - @Test - fun merge_shouldAddEvents_whenMergingBackward() { - monarchy.runTransactionSync { realm -> - val chunk1: ChunkEntity = realm.createObject() - val chunk2: ChunkEntity = realm.createObject() - chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) - chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) - chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS) - chunk1.timelineEvents.size shouldBeEqualTo 60 - } - } - - @Test - fun merge_shouldAddOnlyDifferentEvents_whenMergingBackward() { - monarchy.runTransactionSync { realm -> - val chunk1: ChunkEntity = realm.createObject() - val chunk2: ChunkEntity = realm.createObject() - val eventsForChunk1 = createFakeListOfEvents(30) - val eventsForChunk2 = eventsForChunk1 + createFakeListOfEvents(10) - chunk1.isLastForward = true - chunk2.isLastForward = false - chunk1.addAll(ROOM_ID, eventsForChunk1, PaginationDirection.FORWARDS) - chunk2.addAll(ROOM_ID, eventsForChunk2, PaginationDirection.BACKWARDS) - chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS) - chunk1.timelineEvents.size shouldBeEqualTo 40 - chunk1.isLastForward.shouldBeTrue() - } - } - - @Test - fun merge_shouldPrevTokenMerged_whenMergingForwards() { - monarchy.runTransactionSync { realm -> - val chunk1: ChunkEntity = realm.createObject() - val chunk2: ChunkEntity = realm.createObject() - val prevToken = "prev_token" - chunk1.prevToken = prevToken - chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) - chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) - chunk1.merge(ROOM_ID, chunk2, PaginationDirection.FORWARDS) - chunk1.prevToken shouldBeEqualTo prevToken - } - } - - @Test - fun merge_shouldNextTokenMerged_whenMergingBackwards() { - monarchy.runTransactionSync { realm -> - val chunk1: ChunkEntity = realm.createObject() - val chunk2: ChunkEntity = realm.createObject() - val nextToken = "next_token" - chunk1.nextToken = nextToken - chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) - chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) - chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS) - chunk1.nextToken shouldBeEqualTo nextToken - } - } - - private fun ChunkEntity.addAll(roomId: String, - events: List<Event>, - direction: PaginationDirection) { + private fun ChunkEntity.addAll( + roomId: String, + events: List<Event>, + direction: PaginationDirection + ) { events.forEach { event -> val fakeEvent = event.toEntity(roomId, SendState.SYNCED, clock.epochMillis()).let { realm.copyToRealm(it) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/FakeTokenChunkEvent.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/FakeTokenChunkEvent.kt index 657f622c5b75f7603cb7132596f3ac6ed877472a..2e9478ba7ececeab27990826fa1db11e3f3a100c 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/FakeTokenChunkEvent.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/FakeTokenChunkEvent.kt @@ -19,8 +19,9 @@ package org.matrix.android.sdk.session.room.timeline import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.internal.session.room.timeline.TokenChunkEvent -internal data class FakeTokenChunkEvent(override val start: String?, - override val end: String?, - override val events: List<Event> = emptyList(), - override val stateEvents: List<Event> = emptyList() +internal data class FakeTokenChunkEvent( + override val start: String?, + override val end: String?, + override val events: List<Event> = emptyList(), + override val stateEvents: List<Event> = emptyList() ) : TokenChunkEvent diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/PollAggregationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/PollAggregationTest.kt index 61ab6d4b40f301673ac6c32c804f6875ff6e8513..a37d2ce015f68a624c39d8cc944b49a8ec0fbba6 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/PollAggregationTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/PollAggregationTest.kt @@ -38,8 +38,7 @@ import org.matrix.android.sdk.api.session.room.model.message.PollType import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest import java.util.concurrent.CountDownLatch @RunWith(JUnit4::class) @@ -47,9 +46,7 @@ import java.util.concurrent.CountDownLatch class PollAggregationTest : InstrumentedTest { @Test - fun testAllPollUseCases() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + fun testAllPollUseCases() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false) val aliceSession = cryptoTestData.firstSession @@ -60,7 +57,7 @@ class PollAggregationTest : InstrumentedTest { // Bob creates a poll roomFromBobPOV.sendService().sendPoll(PollType.DISCLOSED, pollQuestion, pollOptions) - aliceSession.startSync(true) + aliceSession.syncService().startSync(true) val aliceTimeline = roomFromAlicePOV.timelineService().createTimeline(null, TimelineSettings(30)) aliceTimeline.start() @@ -80,7 +77,7 @@ class PollAggregationTest : InstrumentedTest { } when (lock.count.toInt()) { - TOTAL_TEST_COUNT -> { + TOTAL_TEST_COUNT -> { // Poll has just been created. testInitialPollConditions(pollContent, pollSummary) lock.countDown() @@ -122,7 +119,7 @@ class PollAggregationTest : InstrumentedTest { testEndedPoll(pollSummary) lock.countDown() } - else -> { + else -> { fail("Lock count ${lock.count} didn't handled.") } } @@ -136,9 +133,8 @@ class PollAggregationTest : InstrumentedTest { aliceTimeline.removeAllListeners() - aliceSession.stopSync() + aliceSession.syncService().stopSync() aliceTimeline.dispose() - cryptoTestData.cleanUp(commonTestHelper) } private fun testInitialPollConditions(pollContent: MessagePollContent, pollSummary: PollResponseAggregatedSummary?) { diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/RoomDataHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/RoomDataHelper.kt index 8a4429db456b7845f380ade3c3e5697718ec2b7e..53585ae82abc743a2ca79bf82663d730a301dabd 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/RoomDataHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/RoomDataHelper.kt @@ -41,11 +41,12 @@ object RoomDataHelper { } } - private fun createFakeEvent(type: String, - content: Content? = null, - prevContent: Content? = null, - sender: String = FAKE_TEST_SENDER, - stateKey: String? = null + private fun createFakeEvent( + type: String, + content: Content? = null, + prevContent: Content? = null, + sender: String = FAKE_TEST_SENDER, + stateKey: String? = null ): Event { return Event( type = type, diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt index d5b4a07fc0fd19a43c625acbfeb15c14a8c0d12a..3dbf206e089c12815ecf89dd0ce9c8ebab86e306 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineForwardPaginationTest.kt @@ -34,8 +34,7 @@ import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest import org.matrix.android.sdk.common.checkSendOrder import timber.log.Timber import java.util.concurrent.CountDownLatch @@ -53,9 +52,7 @@ class TimelineForwardPaginationTest : InstrumentedTest { * This test ensure that if we click to permalink, we will be able to go back to the live */ @Test - fun forwardPaginationTest() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + fun forwardPaginationTest() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val numberOfMessagesToSend = 90 val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(false) @@ -140,9 +137,24 @@ class TimelineForwardPaginationTest : InstrumentedTest { aliceTimeline.hasMoreToLoad(Timeline.Direction.BACKWARDS).shouldBeFalse() assertEquals(EventType.STATE_ROOM_CREATE, snapshot.lastOrNull()?.root?.getClearType()) - // 6 for room creation item (backward pagination), 1 for the context, and 50 for the forward pagination - // 6 + 1 + 50 - assertEquals(57, snapshot.size) + + // We explicitly test all the types we expect here, as we expect 51 messages and "some" state events + // But state events can change over time. So this acts as a kinda documentation of what we expect and + // provides a good error message if it doesn't match + + val snapshotTypes = mutableMapOf<String?, Int>() + snapshot.groupingBy { it -> it.root.type }.eachCountTo(snapshotTypes) + // Some state events on room creation + assertEquals("m.room.name", 1, snapshotTypes.remove("m.room.name")) + assertEquals("m.room.guest_access", 1, snapshotTypes.remove("m.room.guest_access")) + assertEquals("m.room.history_visibility", 1, snapshotTypes.remove("m.room.history_visibility")) + assertEquals("m.room.join_rules", 1, snapshotTypes.remove("m.room.join_rules")) + assertEquals("m.room.power_levels", 1, snapshotTypes.remove("m.room.power_levels")) + assertEquals("m.room.create", 1, snapshotTypes.remove("m.room.create")) + assertEquals("m.room.member", 1, snapshotTypes.remove("m.room.member")) + // 50 from pagination + 1 context + assertEquals("m.room.message", 51, snapshotTypes.remove("m.room.message")) + assertEquals("Additional events found in timeline", setOf<String>(), snapshotTypes.keys) } // Alice paginates once again FORWARD for 50 events @@ -151,9 +163,11 @@ class TimelineForwardPaginationTest : InstrumentedTest { // Ask for a forward pagination val snapshot = runBlocking { aliceTimeline.awaitPaginate(Timeline.Direction.FORWARDS, 50) + // We should paginate one more time to check we are at the end now that chunks are not merged. + aliceTimeline.awaitPaginate(Timeline.Direction.FORWARDS, 50) } - // 6 for room creation item (backward pagination),and numberOfMessagesToSend (all the message of the room) - snapshot.size == 6 + numberOfMessagesToSend && + // 7 for room creation item (backward pagination),and numberOfMessagesToSend (all the message of the room) + snapshot.size == 7 + numberOfMessagesToSend && snapshot.checkSendOrder(message, numberOfMessagesToSend, 0) // The timeline is fully loaded @@ -162,7 +176,5 @@ class TimelineForwardPaginationTest : InstrumentedTest { } aliceTimeline.dispose() - - cryptoTestData.cleanUp(commonTestHelper) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt index 6e5fed8df9f2f2c11125f525f80fc0e07ca6db14..7c1a097b2419f80839260ba467464e5fefe48296 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelinePreviousLastForwardTest.kt @@ -20,6 +20,7 @@ import androidx.test.filters.LargeTest import org.amshove.kluent.shouldBeFalse import org.amshove.kluent.shouldBeTrue import org.junit.FixMethodOrder +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @@ -33,13 +34,13 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.checkSendOrder import timber.log.Timber import java.util.concurrent.CountDownLatch @RunWith(JUnit4::class) @FixMethodOrder(MethodSorters.JVM) +@Ignore("This test will be ignored until it is fixed") @LargeTest class TimelinePreviousLastForwardTest : InstrumentedTest { @@ -48,9 +49,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest { */ @Test - fun previousLastForwardTest() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + fun previousLastForwardTest() = CommonTestHelper.runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false) val aliceSession = cryptoTestData.firstSession @@ -74,8 +73,12 @@ class TimelinePreviousLastForwardTest : InstrumentedTest { Timber.w(" event ${it.root}") } - // Ok, we have the 8 first messages of the initial sync (room creation and bob invite and join events) - snapshot.size == 8 + // Ok, we have the 9 first messages of the initial sync (room creation and bob invite and join events) + // create + // join alice + // power_levels, join_rules, history_visibility, guest_access, name + // invite, join bob + snapshot.size == 9 } bobTimeline.addListener(eventsListener) @@ -87,7 +90,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest { } // Bob stop to sync - bobSession.stopSync() + bobSession.syncService().stopSync() val firstMessage = "First messages from Alice" // Alice sends 30 messages @@ -100,7 +103,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest { .eventId // Bob start to sync - bobSession.startSync(true) + bobSession.syncService().startSync(true) run { val lock = CountDownLatch(1) @@ -124,7 +127,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest { } // Bob stop to sync - bobSession.stopSync() + bobSession.syncService().stopSync() val secondMessage = "Second messages from Alice" // Alice sends again 30 messages @@ -135,7 +138,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest { ) // Bob start to sync - bobSession.startSync(true) + bobSession.syncService().startSync(true) run { val lock = CountDownLatch(1) @@ -192,7 +195,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest { Timber.w(" event ${it.root}") } - snapshot.size == 44 // 8 + 1 + 35 + snapshot.size == 45 // 9 + 1 + 35 } bobTimeline.addListener(eventsListener) @@ -220,14 +223,15 @@ class TimelinePreviousLastForwardTest : InstrumentedTest { // Bob can see the first event of the room (so Back pagination has worked) snapshot.lastOrNull()?.root?.getClearType() == EventType.STATE_ROOM_CREATE && - // 8 for room creation item 60 message from Alice - snapshot.size == 68 && // 8 + 60 + // 9 for room creation item 60 message from Alice + snapshot.size == 69 && // 9 + 60U snapshot.checkSendOrder(secondMessage, 30, 0) && snapshot.checkSendOrder(firstMessage, 30, 30) } bobTimeline.addListener(eventsListener) + bobTimeline.paginate(Timeline.Direction.FORWARDS, 50) bobTimeline.paginate(Timeline.Direction.FORWARDS, 50) commonTestHelper.await(lock) @@ -238,7 +242,5 @@ class TimelinePreviousLastForwardTest : InstrumentedTest { } bobTimeline.dispose() - - cryptoTestData.cleanUp(commonTestHelper) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineSimpleBackPaginationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineSimpleBackPaginationTest.kt index 42f710d7cf431f2a90f14fb56e8b61b05cea4674..59b3b1453229c135340bba60a27f831b0ca78c22 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineSimpleBackPaginationTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineSimpleBackPaginationTest.kt @@ -20,6 +20,7 @@ import androidx.test.filters.LargeTest import kotlinx.coroutines.runBlocking import org.amshove.kluent.internal.assertEquals import org.junit.FixMethodOrder +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @@ -32,19 +33,17 @@ import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest import org.matrix.android.sdk.common.TestConstants @RunWith(JUnit4::class) @FixMethodOrder(MethodSorters.JVM) @LargeTest +@Ignore class TimelineSimpleBackPaginationTest : InstrumentedTest { @Test - fun timeline_backPaginate_shouldReachEndOfTimeline() { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + fun timeline_backPaginate_shouldReachEndOfTimeline() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val numberOfMessagesToSent = 200 val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(false) @@ -102,6 +101,5 @@ class TimelineSimpleBackPaginationTest : InstrumentedTest { assertEquals(numberOfMessagesToSent, onlySentEvents.size) bobTimeline.dispose() - cryptoTestData.cleanUp(commonTestHelper) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt index 02430dda745a541292cdcb9f079c2b328504846c..27ea0e1c3c07743a10a892a7a498accfa1fcc9ff 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/room/timeline/TimelineWithManyMembersTest.kt @@ -30,8 +30,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings -import org.matrix.android.sdk.common.CommonTestHelper -import org.matrix.android.sdk.common.CryptoTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest import java.util.concurrent.CountDownLatch /** !! Not working with the new timeline @@ -47,15 +46,12 @@ class TimelineWithManyMembersTest : InstrumentedTest { private const val NUMBER_OF_MEMBERS = 6 } - private val commonTestHelper = CommonTestHelper(context()) - private val cryptoTestHelper = CryptoTestHelper(commonTestHelper) - /** * Ensures when someone sends a message to a crowded room, everyone can decrypt the message. */ @Test - fun everyone_should_decrypt_message_in_a_crowded_room() { + fun everyone_should_decrypt_message_in_a_crowded_room() = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithManyMembers(NUMBER_OF_MEMBERS) val sessionForFirstMember = cryptoTestData.firstSession @@ -75,7 +71,7 @@ class TimelineWithManyMembersTest : InstrumentedTest { val timelineForCurrentMember = roomForCurrentMember.timelineService().createTimeline(null, TimelineSettings(30)) timelineForCurrentMember.start() - session.startSync(true) + session.syncService().startSync(true) run { val lock = CountDownLatch(1) @@ -96,7 +92,7 @@ class TimelineWithManyMembersTest : InstrumentedTest { timelineForCurrentMember.addListener(eventsListener) commonTestHelper.await(lock, 600_000) } - session.stopSync() + session.syncService().stopSync() } } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt index e17b7efbd6d9d348c39ebb02ba9c99fc625b1bdc..7c97426c391a675f4c2659b030e12ef214162eb6 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/search/SearchMessagesTest.kt @@ -26,9 +26,8 @@ import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.search.SearchResult -import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest import org.matrix.android.sdk.common.CryptoTestData -import org.matrix.android.sdk.common.CryptoTestHelper @RunWith(JUnit4::class) @FixMethodOrder(MethodSorters.JVM) @@ -74,9 +73,7 @@ class SearchMessagesTest : InstrumentedTest { } } - private fun doTest(block: suspend (CryptoTestData) -> SearchResult) { - val commonTestHelper = CommonTestHelper(context()) - val cryptoTestHelper = CryptoTestHelper(commonTestHelper) + private fun doTest(block: suspend (CryptoTestData) -> SearchResult) = runCryptoTest(context()) { cryptoTestHelper, commonTestHelper -> val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceInARoom(false) val aliceSession = cryptoTestData.firstSession val aliceRoomId = cryptoTestData.roomId @@ -99,7 +96,5 @@ class SearchMessagesTest : InstrumentedTest { (it.event.content?.get("body") as? String)?.startsWith(MESSAGE).orFalse() }.orFalse() ) - - cryptoTestData.cleanUp(commonTestHelper) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt index b9760c1bfc73f57903a33e04900ae8ddac92d080..0cc0ef57c411e7585ac56ed889e18603551f0d0f 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceCreationTest.kt @@ -22,6 +22,7 @@ import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.FixMethodOrder +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @@ -40,7 +41,7 @@ import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent import org.matrix.android.sdk.api.session.space.JoinSpaceResult -import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest import org.matrix.android.sdk.common.SessionTestParams @RunWith(JUnit4::class) @@ -49,8 +50,7 @@ import org.matrix.android.sdk.common.SessionTestParams class SpaceCreationTest : InstrumentedTest { @Test - fun createSimplePublicSpace() { - val commonTestHelper = CommonTestHelper(context()) + fun createSimplePublicSpace() = runSessionTest(context()) { commonTestHelper -> val session = commonTestHelper.createAccount("Hubble", SessionTestParams(true)) val roomName = "My Space" val topic = "A public space for test" @@ -96,13 +96,11 @@ class SpaceCreationTest : InstrumentedTest { ?.toModel<RoomHistoryVisibilityContent>()?.historyVisibility assertEquals("Public space room should be world readable", RoomHistoryVisibility.WORLD_READABLE, historyVisibility) - - commonTestHelper.signOutAndClose(session) } @Test - fun testJoinSimplePublicSpace() { - val commonTestHelper = CommonTestHelper(context()) + @Ignore + fun testJoinSimplePublicSpace() = runSessionTest(context()) { commonTestHelper -> val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true)) val bobSession = commonTestHelper.createAccount("bob", SessionTestParams(true)) @@ -134,8 +132,7 @@ class SpaceCreationTest : InstrumentedTest { } @Test - fun testSimplePublicSpaceWithChildren() { - val commonTestHelper = CommonTestHelper(context()) + fun testSimplePublicSpaceWithChildren() = runSessionTest(context()) { commonTestHelper -> val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true)) val bobSession = commonTestHelper.createAccount("bob", SessionTestParams(true)) @@ -204,8 +201,5 @@ class SpaceCreationTest : InstrumentedTest { // ).size // // assertEquals("Unexpected number of joined children", 1, childCount) - - commonTestHelper.signOutAndClose(aliceSession) - commonTestHelper.signOutAndClose(bobSession) } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt index 6a17cb74add602e49100d148a961a6615fe2c450..5396251438d56fbe6d230220f833f0851a0e78c2 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/session/space/SpaceHierarchyTest.kt @@ -29,8 +29,8 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.junit.runners.MethodSorters import org.matrix.android.sdk.InstrumentedTest -import org.matrix.android.sdk.api.query.ActiveSpaceFilter import org.matrix.android.sdk.api.query.QueryStringValue +import org.matrix.android.sdk.api.query.SpaceFilter import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toContent @@ -48,6 +48,7 @@ import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.powerlevels.Role import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest import org.matrix.android.sdk.common.SessionTestParams @RunWith(JUnit4::class) @@ -55,8 +56,7 @@ import org.matrix.android.sdk.common.SessionTestParams class SpaceHierarchyTest : InstrumentedTest { @Test - fun createCanonicalChildRelation() { - val commonTestHelper = CommonTestHelper(context()) + fun createCanonicalChildRelation() = runSessionTest(context()) { commonTestHelper -> val session = commonTestHelper.createAccount("John", SessionTestParams(true)) val spaceName = "My Space" @@ -173,8 +173,7 @@ class SpaceHierarchyTest : InstrumentedTest { // } @Test - fun testFilteringBySpace() { - val commonTestHelper = CommonTestHelper(context()) + fun testFilteringBySpace() = CommonTestHelper.runSessionTest(context()) { commonTestHelper -> val session = commonTestHelper.createAccount("John", SessionTestParams(true)) val spaceAInfo = createPublicSpace( @@ -185,12 +184,12 @@ class SpaceHierarchyTest : InstrumentedTest { ) /* val spaceBInfo = */ createPublicSpace( - session, "SpaceB", listOf( - Triple("B1", true /*auto-join*/, true/*canonical*/), - Triple("B2", true, true), - Triple("B3", true, true) - ) - ) + session, "SpaceB", listOf( + Triple("B1", true /*auto-join*/, true/*canonical*/), + Triple("B2", true, true), + Triple("B3", true, true) + ) + ) val spaceCInfo = createPublicSpace( session, "SpaceC", listOf( @@ -249,15 +248,14 @@ class SpaceHierarchyTest : InstrumentedTest { Thread.sleep(6_000) val orphansUpdate = session.roomService().getRoomSummaries(roomSummaryQueryParams { - activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null) + spaceFilter = SpaceFilter.OrphanRooms }) assertEquals("Unexpected number of orphan rooms ${orphansUpdate.map { it.name }}", 2, orphansUpdate.size) } @Test @Ignore("This test will be ignored until it is fixed") - fun testBreakCycle() { - val commonTestHelper = CommonTestHelper(context()) + fun testBreakCycle() = CommonTestHelper.runSessionTest(context()) { commonTestHelper -> val session = commonTestHelper.createAccount("John", SessionTestParams(true)) val spaceAInfo = createPublicSpace( @@ -302,8 +300,7 @@ class SpaceHierarchyTest : InstrumentedTest { } @Test - fun testLiveFlatChildren() { - val commonTestHelper = CommonTestHelper(context()) + fun testLiveFlatChildren() = CommonTestHelper.runSessionTest(context()) { commonTestHelper -> val session = commonTestHelper.createAccount("John", SessionTestParams(true)) val spaceAInfo = createPublicSpace( @@ -390,84 +387,87 @@ class SpaceHierarchyTest : InstrumentedTest { val roomIds: List<String> ) - private fun createPublicSpace(session: Session, - spaceName: String, - childInfo: List<Triple<String, Boolean, Boolean?>> + private fun createPublicSpace( + session: Session, + spaceName: String, + childInfo: List<Triple<String, Boolean, Boolean?>> /** Name, auto-join, canonical*/ ): TestSpaceCreationResult { - val commonTestHelper = CommonTestHelper(context()) var spaceId = "" var roomIds: List<String> = emptyList() - commonTestHelper.waitWithLatch { latch -> - spaceId = session.spaceService().createSpace(spaceName, "Test Topic", null, true) - val syncedSpace = session.spaceService().getSpace(spaceId) - val viaServers = listOf(session.sessionParams.homeServerHost ?: "") - - roomIds = childInfo.map { entry -> - session.roomService().createRoom(CreateRoomParams().apply { name = entry.first }) - } - roomIds.forEachIndexed { index, roomId -> - syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second) - val canonical = childInfo[index].third - if (canonical != null) { - session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers) + runSessionTest(context()) { commonTestHelper -> + commonTestHelper.waitWithLatch { latch -> + spaceId = session.spaceService().createSpace(spaceName, "Test Topic", null, true) + val syncedSpace = session.spaceService().getSpace(spaceId) + val viaServers = listOf(session.sessionParams.homeServerHost ?: "") + + roomIds = childInfo.map { entry -> + session.roomService().createRoom(CreateRoomParams().apply { name = entry.first }) + } + roomIds.forEachIndexed { index, roomId -> + syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second) + val canonical = childInfo[index].third + if (canonical != null) { + session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers) + } } + latch.countDown() } - latch.countDown() } return TestSpaceCreationResult(spaceId, roomIds) } - private fun createPrivateSpace(session: Session, - spaceName: String, - childInfo: List<Triple<String, Boolean, Boolean?>> + private fun createPrivateSpace( + session: Session, + spaceName: String, + childInfo: List<Triple<String, Boolean, Boolean?>> /** Name, auto-join, canonical*/ ): TestSpaceCreationResult { - val commonTestHelper = CommonTestHelper(context()) var spaceId = "" var roomIds: List<String> = emptyList() - commonTestHelper.waitWithLatch { latch -> - spaceId = session.spaceService().createSpace(spaceName, "My Private Space", null, false) - val syncedSpace = session.spaceService().getSpace(spaceId) - val viaServers = listOf(session.sessionParams.homeServerHost ?: "") - roomIds = - childInfo.map { entry -> - val homeServerCapabilities = session - .homeServerCapabilitiesService() - .getHomeServerCapabilities() - session.roomService().createRoom(CreateRoomParams().apply { - name = entry.first - this.featurePreset = RestrictedRoomPreset( - homeServerCapabilities, - listOf( - RoomJoinRulesAllowEntry.restrictedToRoom(spaceId) - ) - ) - }) + runSessionTest(context()) { commonTestHelper -> + commonTestHelper.waitWithLatch { latch -> + spaceId = session.spaceService().createSpace(spaceName, "My Private Space", null, false) + val syncedSpace = session.spaceService().getSpace(spaceId) + val viaServers = listOf(session.sessionParams.homeServerHost ?: "") + roomIds = + childInfo.map { entry -> + val homeServerCapabilities = session + .homeServerCapabilitiesService() + .getHomeServerCapabilities() + session.roomService().createRoom(CreateRoomParams().apply { + name = entry.first + this.featurePreset = RestrictedRoomPreset( + homeServerCapabilities, + listOf( + RoomJoinRulesAllowEntry.restrictedToRoom(spaceId) + ) + ) + }) + } + roomIds.forEachIndexed { index, roomId -> + syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second) + val canonical = childInfo[index].third + if (canonical != null) { + session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers) } - roomIds.forEachIndexed { index, roomId -> - syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second) - val canonical = childInfo[index].third - if (canonical != null) { - session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers) } + latch.countDown() } - latch.countDown() } return TestSpaceCreationResult(spaceId, roomIds) } @Test - fun testRootSpaces() { - val commonTestHelper = CommonTestHelper(context()) + fun testRootSpaces() = runSessionTest(context()) { commonTestHelper -> val session = commonTestHelper.createAccount("John", SessionTestParams(true)) /* val spaceAInfo = */ createPublicSpace( - session, "SpaceA", listOf( - Triple("A1", true /*auto-join*/, true/*canonical*/), - Triple("A2", true, true) - ) - ) + session, "SpaceA", listOf( + Triple("A1", true /*auto-join*/, true/*canonical*/), + Triple("A2", true, true) + ) + ) val spaceBInfo = createPublicSpace( session, "SpaceB", listOf( @@ -506,13 +506,10 @@ class SpaceHierarchyTest : InstrumentedTest { } assertEquals("Unexpected number of root spaces ${rootSpaces.map { it.name }}", 2, rootSpaces.size) - - commonTestHelper.signOutAndClose(session) } @Test - fun testParentRelation() { - val commonTestHelper = CommonTestHelper(context()) + fun testParentRelation() = runSessionTest(context()) { commonTestHelper -> val aliceSession = commonTestHelper.createAccount("Alice", SessionTestParams(true)) val bobSession = commonTestHelper.createAccount("Bib", SessionTestParams(true)) @@ -604,8 +601,5 @@ class SpaceHierarchyTest : InstrumentedTest { bobSession.getRoomSummary(bobRoomId)?.flattenParentIds?.contains(spaceAInfo.spaceId) == true } } - - commonTestHelper.signOutAndClose(aliceSession) - commonTestHelper.signOutAndClose(bobSession) } } diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt index 3fe8d156962767af7871664bf24bd88baa5af343..556579942b9f1667c53769f003517a982761a869 100644 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt @@ -26,14 +26,14 @@ internal class InlineMaths(private val delimiter: InlineDelimiter) : CustomNode( override fun getOpeningDelimiter(): String { return when (delimiter) { - InlineDelimiter.SINGLE_DOLLAR -> "$" + InlineDelimiter.SINGLE_DOLLAR -> "$" InlineDelimiter.ROUND_BRACKET_ESCAPED -> "\\(" } } override fun getClosingDelimiter(): String { return when (delimiter) { - InlineDelimiter.SINGLE_DOLLAR -> "$" + InlineDelimiter.SINGLE_DOLLAR -> "$" InlineDelimiter.ROUND_BRACKET_ESCAPED -> "\\)" } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt index 867e066e604f83195213c57cd781882a3e570432..82f39806c0392e6359496804106fede495ba17da 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt @@ -177,7 +177,7 @@ object MatrixPatterns { * - "@alice:domain.org".getDomain() will return "domain.org" * - "@bob:domain.org:3455".getDomain() will return "domain.org:3455" */ - fun String.getDomain(): String { + fun String.getServerName(): String { if (BuildConfig.DEBUG && !isUserId(this)) { // They are some invalid userId localpart in the wild, but the domain part should be there anyway Timber.w("Not a valid user ID: $this") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/RoomDisplayNameFallbackProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/RoomDisplayNameFallbackProvider.kt index a34dbcc1965a08741ed6d66bf0d2b8e61ca732f8..3c376b55ee15677a8169459d2e03777ad6479238 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/RoomDisplayNameFallbackProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/RoomDisplayNameFallbackProvider.kt @@ -16,6 +16,14 @@ package org.matrix.android.sdk.api +/** + * This interface exists to let the implementation provide localized room display name fallback. + * The methods can be called when the room has no name, i.e. its `m.room.name` state event does not exist or + * the name in it is an empty String. + * It allows the SDK to store the room name fallback into the local storage and so let the client do + * queries on the room name. + * *Limitation*: if the locale of the device changes, the methods will not be called again. + */ interface RoomDisplayNameFallbackProvider { fun getNameForRoomInvite(): String fun getNameForEmptyRoom(isDirect: Boolean, leftMemberNames: List<String>): String diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt index 5a19df90c4f99eb105f630241bc411ad541cdf1e..5ae70e1978c0e5bc9398560a12b81123b6a369ca 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt @@ -28,9 +28,11 @@ import org.matrix.android.sdk.api.session.Session * This interface defines methods to authenticate or to create an account to a matrix server. */ interface AuthenticationService { + /** * Request the supported login flows for this homeserver. - * This is the first method to call to be able to get a wizard to login or to create an account + * This is the first method to call to be able to get a wizard to login or to create an account. + * @param homeServerConnectionConfig contains the homeserver URL to login to, a wellKnown lookup will be attempted. */ suspend fun getLoginFlow(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult @@ -66,7 +68,7 @@ interface AuthenticationService { /** * True when login and password has been sent with success to the homeserver. */ - val isRegistrationStarted: Boolean + fun isRegistrationStarted(): Boolean /** * Cancel pending login or pending registration. @@ -93,14 +95,18 @@ interface AuthenticationService { /** * Create a session after a SSO successful login. */ - suspend fun createSessionFromSso(homeServerConnectionConfig: HomeServerConnectionConfig, - credentials: Credentials): Session + suspend fun createSessionFromSso( + homeServerConnectionConfig: HomeServerConnectionConfig, + credentials: Credentials + ): Session /** * Perform a wellknown request, using the domain from the matrixId. */ - suspend fun getWellKnownData(matrixId: String, - homeServerConnectionConfig: HomeServerConnectionConfig?): WellknownResult + suspend fun getWellKnownData( + matrixId: String, + homeServerConnectionConfig: HomeServerConnectionConfig? + ): WellknownResult /** * Authenticate with a matrixId and a password. @@ -111,9 +117,11 @@ interface AuthenticationService { * @param initialDeviceName the initial device name * @param deviceId the device id, optional. If not provided or null, the server will generate one. */ - suspend fun directAuthentication(homeServerConnectionConfig: HomeServerConnectionConfig, - matrixId: String, - password: String, - initialDeviceName: String, - deviceId: String? = null): Session + suspend fun directAuthentication( + homeServerConnectionConfig: HomeServerConnectionConfig, + matrixId: String, + password: String, + initialDeviceName: String, + deviceId: String? = null + ): Session } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/converter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/converter.kt index 80630bc4e7fbf7eafa3015b21bae6b07a6e8a955..e2f16ceee80217d1a7469da18e9ea3b7f1a46cc7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/converter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/converter.kt @@ -41,8 +41,10 @@ import org.matrix.android.sdk.api.auth.registration.TermPolicies * @param userLanguage the user language * @param defaultLanguage the default language to use if the user language is not found for a policy in registrationFlowResponse */ -fun TermPolicies.toLocalizedLoginTerms(userLanguage: String, - defaultLanguage: String = "en"): List<LocalizedFlowDataLoginTerms> { +fun TermPolicies.toLocalizedLoginTerms( + userLanguage: String, + defaultLanguage: String = "en" +): List<LocalizedFlowDataLoginTerms> { val result = ArrayList<LocalizedFlowDataLoginTerms>() val policies = get("policies") @@ -67,8 +69,8 @@ fun TermPolicies.toLocalizedLoginTerms(userLanguage: String, // Search for language policy.keys.forEach { policyKey -> when (policyKey) { - "version" -> Unit // Ignore - userLanguage -> { + "version" -> Unit // Ignore + userLanguage -> { // We found the data for the user language userLanguageUrlAndName = extractUrlAndName(policy[policyKey]) } @@ -76,7 +78,7 @@ fun TermPolicies.toLocalizedLoginTerms(userLanguage: String, // We found default language defaultLanguageUrlAndName = extractUrlAndName(policy[policyKey]) } - else -> { + else -> { if (firstUrlAndName == null) { // Get at least some data firstUrlAndName = extractUrlAndName(policy[policyKey]) @@ -87,7 +89,7 @@ fun TermPolicies.toLocalizedLoginTerms(userLanguage: String, // Copy found language data by priority when { - userLanguageUrlAndName != null -> { + userLanguageUrlAndName != null -> { localizedFlowDataLoginTermsLocalizedUrl = userLanguageUrlAndName!!.url localizedFlowDataLoginTermsLocalizedName = userLanguageUrlAndName!!.name } @@ -95,7 +97,7 @@ fun TermPolicies.toLocalizedLoginTerms(userLanguage: String, localizedFlowDataLoginTermsLocalizedUrl = defaultLanguageUrlAndName!!.url localizedFlowDataLoginTermsLocalizedName = defaultLanguageUrlAndName!!.name } - firstUrlAndName != null -> { + firstUrlAndName != null -> { localizedFlowDataLoginTermsLocalizedUrl = firstUrlAndName!!.url localizedFlowDataLoginTermsLocalizedName = firstUrlAndName!!.name } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt index c2c1f043bbf4aa3b4ec69ebe46b2511fd0ab36fd..c3f0221bb896242efb6ab7578d6f8c12767e20ca 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/HomeServerConnectionConfig.kt @@ -195,7 +195,7 @@ data class HomeServerConnectionConfig( * - https://www.ssi.gouv.fr/uploads/2017/07/anssi-guide-recommandations_de_securite_relatives_a_tls-v1.2.pdf * - https://developer.android.com/reference/javax/net/ssl/SSLEngine * - * @param tlsLimitations true to use Tls limitations + * @param tlsLimitations true to use Tls limitations * @param enableCompatibilityMode set to true for Android < 20 * @return this builder */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt index a0733dda978263754d95b6b841864e356908243a..773f5a8cc4b0878f6f7d00d1614081ad74491e42 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt @@ -66,17 +66,17 @@ data class SsoIdentityProvider( private fun toPriority(): Int { return when (brand) { // We are on Android, so user is more likely to have a Google account - BRAND_GOOGLE -> 5 + BRAND_GOOGLE -> 5 // Facebook is also an important SSO provider BRAND_FACEBOOK -> 4 // Twitter is more for professionals - BRAND_TWITTER -> 3 + BRAND_TWITTER -> 3 // Here it's very for techie people BRAND_GITHUB, - BRAND_GITLAB -> 2 + BRAND_GITLAB -> 2 // And finally, if the account has been created with an iPhone... - BRAND_APPLE -> 1 - else -> 0 + BRAND_APPLE -> 1 + else -> 0 } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt index 3232025de39a0c3c2271a7dbc34ed66e8466309a..5b8d2328c769ef3c49d192eac13c232e4226bd56 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/login/LoginWizard.kt @@ -39,10 +39,12 @@ interface LoginWizard { * @param deviceId the device id, optional. If not provided or null, the server will generate one. * @return a [Session] if the login is successful */ - suspend fun login(login: String, - password: String, - initialDeviceName: String, - deviceId: String? = null): Session + suspend fun login( + login: String, + password: String, + initialDeviceName: String, + deviceId: String? = null + ): Session /** * Exchange a login token to an access token. @@ -63,14 +65,14 @@ interface LoginWizard { * [resetPasswordMailConfirmed] is successfully called. * * @param email an email previously associated to the account the user wants the password to be reset. - * @param newPassword the desired new password */ - suspend fun resetPassword(email: String, - newPassword: String) + suspend fun resetPassword(email: String) /** * Confirm the new password, once the user has checked their email * When this method succeed, tha account password will be effectively modified. + * + * @param newPassword the desired new password */ - suspend fun resetPasswordMailConfirmed() + suspend fun resetPasswordMailConfirmed(newPassword: String) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt index 1252e93b84848d72b678977b269e37a73b603b9e..98542d208650aa682b033582d05627ecc7bf8009 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationFlowResponse.kt @@ -88,15 +88,15 @@ fun RegistrationFlowResponse.toFlowResult(): FlowResult { val isMandatory = flows?.all { type in it.stages.orEmpty() } == true val stage = when (type) { - LoginFlowTypes.RECAPTCHA -> Stage.ReCaptcha( + LoginFlowTypes.RECAPTCHA -> Stage.ReCaptcha( isMandatory, ((params?.get(type) as? Map<*, *>)?.get("public_key") as? String) ?: "" ) - LoginFlowTypes.DUMMY -> Stage.Dummy(isMandatory) - LoginFlowTypes.TERMS -> Stage.Terms(isMandatory, params?.get(type) as? TermPolicies ?: emptyMap<String, String>()) + LoginFlowTypes.DUMMY -> Stage.Dummy(isMandatory) + LoginFlowTypes.TERMS -> Stage.Terms(isMandatory, params?.get(type) as? TermPolicies ?: emptyMap<String, String>()) LoginFlowTypes.EMAIL_IDENTITY -> Stage.Email(isMandatory) - LoginFlowTypes.MSISDN -> Stage.Msisdn(isMandatory) - else -> Stage.Other(isMandatory, type, (params?.get(type) as? Map<*, *>)) + LoginFlowTypes.MSISDN -> Stage.Msisdn(isMandatory) + else -> Stage.Other(isMandatory, type, (params?.get(type) as? Map<*, *>)) } if (type in completedStages.orEmpty()) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationResult.kt index 439b4beb4169bc1e8ed955edc7c57899b4ba3bd4..9e6b2b3ad91cbd3966ca85550b33637e49641b54 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationResult.kt @@ -18,13 +18,31 @@ package org.matrix.android.sdk.api.auth.registration import org.matrix.android.sdk.api.session.Session -// Either a session or an object containing data about registration stages +/** + * Either a session or an object containing data about registration stages. + */ sealed class RegistrationResult { + /** + * The registration is successful, the [Session] is provided. + */ data class Success(val session: Session) : RegistrationResult() + + /** + * The registration still miss some steps. See [FlowResult] to know the details. + */ data class FlowResponse(val flowResult: FlowResult) : RegistrationResult() } +/** + * Information about the missing and completed [Stage]. + */ data class FlowResult( + /** + * List of missing stages. + */ val missingStages: List<Stage>, + /** + * List of completed stages. + */ val completedStages: List<Stage> ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt index 0cda64499f126def2d5d006c0b1b1bca80661199..995fd27acecfd2241b099b4f9c5e4e502feb2ddf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/RegistrationWizard.kt @@ -54,9 +54,11 @@ interface RegistrationWizard { * @param password the desired password * @param initialDeviceDisplayName the device display name */ - suspend fun createAccount(userName: String?, - password: String?, - initialDeviceDisplayName: String?): RegistrationResult + suspend fun createAccount( + userName: String?, + password: String?, + initialDeviceDisplayName: String? + ): RegistrationResult /** * Perform the "m.login.recaptcha" stage. @@ -109,14 +111,14 @@ interface RegistrationWizard { suspend fun checkIfEmailHasBeenValidated(delayMillis: Long): RegistrationResult /** - * This is the current ThreePid, waiting for validation. The SDK will store it in database, so it can be + * Returns the current ThreePid, waiting for validation. The SDK will store it in database, so it can be * restored even if the app has been killed during the registration */ - val currentThreePid: String? + fun getCurrentThreePid(): String? /** - * True when login and password have been sent with success to the homeserver, i.e. [createAccount] has been + * Return true when login and password have been sent with success to the homeserver, i.e. [createAccount] has been * called successfully. */ - val isRegistrationStarted: Boolean + fun isRegistrationStarted(): Boolean } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/Stage.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/Stage.kt index c21b667cf7f6817292ba3eee9a959267894eff00..281b0c28081c07f9e7ae00f4e19314f528eda3ef 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/Stage.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/registration/Stage.kt @@ -16,25 +16,40 @@ package org.matrix.android.sdk.api.auth.registration +/** + * Registration stages. + */ sealed class Stage(open val mandatory: Boolean) { - // m.login.recaptcha + /** + * m.login.recaptcha stage. + */ data class ReCaptcha(override val mandatory: Boolean, val publicKey: String) : Stage(mandatory) - // m.login.email.identity + /** + * m.login.email.identity stage. + */ data class Email(override val mandatory: Boolean) : Stage(mandatory) - // m.login.msisdn + /** + * m.login.msisdn stage. + */ data class Msisdn(override val mandatory: Boolean) : Stage(mandatory) - // m.login.dummy, can be mandatory if there is no other stages. In this case the account cannot be created by just sending a username - // and a password, the dummy stage has to be done + /** + * m.login.dummy, can be mandatory if there is no other stages. In this case the account cannot be created by just sending a username + * and a password, the dummy stage has to be done. + */ data class Dummy(override val mandatory: Boolean) : Stage(mandatory) - // Undocumented yet: m.login.terms + /** + * Undocumented yet: m.login.terms stage. + */ data class Terms(override val mandatory: Boolean, val policies: TermPolicies) : Stage(mandatory) - // For unknown stages + /** + * For unknown stages. + */ data class Other(override val mandatory: Boolean, val type: String, val params: Map<*, *>?) : Stage(mandatory) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt index 56257db79c42f2438639bed8eb0dd0cc36fe97b3..ea5570db1cda325ec3247bdd949ce4f93166fbbb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt @@ -26,9 +26,11 @@ sealed class WellknownResult { * Retrieve the specific piece of information from the user in a way which fits within the existing client user experience, * if the client is inclined to do so. Failure can take place instead if no good user experience for this is possible at this point. */ - data class Prompt(val homeServerUrl: String, - val identityServerUrl: String?, - val wellKnown: WellKnown) : WellknownResult() + data class Prompt( + val homeServerUrl: String, + val identityServerUrl: String?, + val wellKnown: WellKnown + ) : WellknownResult() /** * Stop the current auto-discovery mechanism. If no more auto-discovery mechanisms are available, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/cache/CacheStrategy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/cache/CacheStrategy.kt index 2880d851d6c2070d63b1cbd6b4dd4bf85031c73f..ddf76d6e42372b7dd07035290a2c9771d740bfa5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/cache/CacheStrategy.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/cache/CacheStrategy.kt @@ -17,13 +17,19 @@ package org.matrix.android.sdk.api.cache sealed class CacheStrategy { - // Data is always fetched from the server + /** + * Data is always fetched from the server. + */ object NoCache : CacheStrategy() - // Once data is retrieved, it is stored for the provided amount of time. - // In case of error, and if strict is set to false, the cache can be returned if available + /** + * Once data is retrieved, it is stored for the provided amount of time. + * In case of error, and if strict is set to false, the cache can be returned if available + */ data class TtlCache(val validityDurationInMillis: Long, val strict: Boolean) : CacheStrategy() - // Once retrieved, the data is stored in cache and will be always get from the cache + /** + * Once retrieved, the data is stored in cache and will be always get from the cache. + */ object InfiniteCache : CacheStrategy() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/extensions/Strings.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/extensions/Strings.kt index 5e1350e32791ac60019659e3356511fc3b353708..9f979098f8e0c24b5fe12de68e6425f827732b7c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/extensions/Strings.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/extensions/Strings.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.extensions fun CharSequence.ensurePrefix(prefix: CharSequence): CharSequence { return when { startsWith(prefix) -> this - else -> "$prefix$this" + else -> "$prefix$this" } } @@ -27,3 +27,8 @@ fun CharSequence.ensurePrefix(prefix: CharSequence): CharSequence { * Append a new line and then the provided string. */ fun StringBuilder.appendNl(str: String) = append("\n").append(str) + +/** + * Returns null if the string is empty. + */ +fun String.ensureNotEmpty() = ifEmpty { null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt index be139fd82bd44c8c61e0182256d4962e63f449f5..7d4f553bede46b57f736d154a2ce32f37f521ad1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Failure.kt @@ -37,7 +37,9 @@ sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) { data class ServerError(val error: MatrixError, val httpCode: Int) : Failure(RuntimeException(error.toString())) object SuccessError : Failure(RuntimeException(RuntimeException("SuccessResult is false"))) - // When server send an error, but it cannot be interpreted as a MatrixError + /** + * When server send an error, but it cannot be interpreted as a MatrixError. + */ data class OtherServerError(val errorBody: String, val httpCode: Int) : Failure(RuntimeException("HTTP $httpCode: $errorBody")) data class RegistrationFlowError(val registrationFlowResponse: RegistrationFlowResponse) : Failure(RuntimeException(registrationFlowResponse.toString())) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ssl/Fingerprint.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ssl/Fingerprint.kt index 93e93fd292115bef726b53d7efa9f0ca0f8e7c62..2fc04013f9e6198c921788e0daabb7adb8f3e92c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ssl/Fingerprint.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/network/ssl/Fingerprint.kt @@ -36,7 +36,7 @@ data class Fingerprint( internal fun matchesCert(cert: X509Certificate): Boolean { val o: Fingerprint? = when (hashType) { HashType.SHA256 -> newSha256Fingerprint(cert) - HashType.SHA1 -> newSha1Fingerprint(cert) + HashType.SHA1 -> newSha1Fingerprint(cert) } return equals(o) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt index 368ff986613783037cd0b44771d9d8ebdfb9fdcd..f08c86885d7e2179e40d26fe10d437e82ee2f772 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/QueryStringValue.kt @@ -20,20 +20,52 @@ package org.matrix.android.sdk.api.query * Basic query language. All these cases are mutually exclusive. */ sealed interface QueryStringValue { - sealed interface ContentQueryStringValue : QueryStringValue { - val string: String - val case: Case - } - + /** + * No condition, i.e. there will be no test on the tested field. + */ object NoCondition : QueryStringValue + + /** + * The tested field has to be null. + */ object IsNull : QueryStringValue + + /** + * The tested field has to be not null. + */ object IsNotNull : QueryStringValue + + /** + * The tested field has to be empty. + */ object IsEmpty : QueryStringValue + + /** + * The tested field has to not empty. + */ object IsNotEmpty : QueryStringValue + /** + * Interface to check String content. + */ + sealed interface ContentQueryStringValue : QueryStringValue { + val string: String + val case: Case + } + + /** + * The tested field must match the [string]. + */ data class Equals(override val string: String, override val case: Case = Case.SENSITIVE) : ContentQueryStringValue + + /** + * The tested field must contain the [string]. + */ data class Contains(override val string: String, override val case: Case = Case.SENSITIVE) : ContentQueryStringValue + /** + * Case enum for [ContentQueryStringValue]. + */ enum class Case { /** * Match query sensitive to case. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomCategoryFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomCategoryFilter.kt index c8ccc4c8a3ec3d8e9abce5ffee7591675028120f..c2117adbd356caa35471548ca8ec43c78b469e99 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomCategoryFilter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomCategoryFilter.kt @@ -16,9 +16,23 @@ package org.matrix.android.sdk.api.query +/** + * To filter by Room category. + * @see [org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams] + */ enum class RoomCategoryFilter { + /** + * Get only the DM, i.e. the rooms referenced in `m.direct` account data. + */ ONLY_DM, + + /** + * Get only the Room, not the DM, i.e. the rooms not referenced in `m.direct` account data. + */ ONLY_ROOMS, + + /** + * Get the room with non-0 notifications. + */ ONLY_WITH_NOTIFICATIONS, - ALL } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomTagQueryFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomTagQueryFilter.kt index 613916bc18a3a4b0d569595bc7a444a40bde45c7..73947f8f7a6e10c9c40b30a2848643cbbcfc9622 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomTagQueryFilter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/RoomTagQueryFilter.kt @@ -16,8 +16,22 @@ package org.matrix.android.sdk.api.query +/** + * Filter room by their tag. + * @see [org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams] + * @see [org.matrix.android.sdk.api.session.room.model.tag.RoomTag] + */ data class RoomTagQueryFilter( + /** + * Set to true to get the rooms which have the tag "m.favourite". + */ val isFavorite: Boolean?, + /** + * Set to true to get the rooms which have the tag "m.lowpriority". + */ val isLowPriority: Boolean?, - val isServerNotice: Boolean? + /** + * Set to true to get the rooms which have the tag "m.server_notice". + */ + val isServerNotice: Boolean?, ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/SpaceFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/SpaceFilter.kt new file mode 100644 index 0000000000000000000000000000000000000000..6383412ffbdf714fa4b2ad8d8391508fc28b223f --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/SpaceFilter.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.query + +/** + * Filter to be used to do room queries regarding the space hierarchy. + * @see [org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams] + */ +sealed interface SpaceFilter { + /** + * Used to get all the rooms that are not in any space. + */ + object OrphanRooms : SpaceFilter + + /** + * Used to get all the rooms that have the provided space in their parent hierarchy. + */ + data class ActiveSpace(val spaceId: String) : SpaceFilter + + /** + * Used to get all the rooms that do not have the provided space in their parent hierarchy. + */ + data class ExcludeSpace(val spaceId: String) : SpaceFilter +} + +/** + * Return a [SpaceFilter.ActiveSpace] if the String is not null, or [SpaceFilter.OrphanRooms]. + */ +fun String?.toActiveSpaceOrOrphanRooms(): SpaceFilter = this?.let { SpaceFilter.ActiveSpace(it) } ?: SpaceFilter.OrphanRooms diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt index 2f1ae8cd87626fe744434bdecd911d40c5118312..b3a629094cb20d79a751600b795c69c8ed6638a1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt @@ -17,8 +17,6 @@ package org.matrix.android.sdk.api.session import androidx.annotation.MainThread -import androidx.lifecycle.LiveData -import kotlinx.coroutines.flow.SharedFlow import okhttp3.OkHttpClient import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.auth.data.SessionParams @@ -37,7 +35,6 @@ import org.matrix.android.sdk.api.session.file.FileService import org.matrix.android.sdk.api.session.group.GroupService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService import org.matrix.android.sdk.api.session.identity.IdentityService -import org.matrix.android.sdk.api.session.initsync.SyncStatusService import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService import org.matrix.android.sdk.api.session.media.MediaService import org.matrix.android.sdk.api.session.openid.OpenIdService @@ -55,8 +52,7 @@ import org.matrix.android.sdk.api.session.signout.SignOutService import org.matrix.android.sdk.api.session.space.SpaceService import org.matrix.android.sdk.api.session.statistics.StatisticsListener import org.matrix.android.sdk.api.session.sync.FilterService -import org.matrix.android.sdk.api.session.sync.SyncState -import org.matrix.android.sdk.api.session.sync.model.SyncResponse +import org.matrix.android.sdk.api.session.sync.SyncService import org.matrix.android.sdk.api.session.terms.TermsService import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService import org.matrix.android.sdk.api.session.typing.TypingUsersTracker @@ -98,59 +94,11 @@ interface Session { @MainThread fun open() - /** - * Requires a one time background sync. - */ - fun requireBackgroundSync() - - /** - * Launches infinite self rescheduling background syncs via the WorkManager. - * - * While dozing, syncs will only occur during maintenance windows. - * For reliability it's recommended to also start a long running foreground service - * along with disabling battery optimizations. - */ - fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long) - - fun stopAnyBackgroundSync() - - /** - * This method start the sync thread. - */ - fun startSync(fromForeground: Boolean) - - /** - * This method stop the sync thread. - */ - fun stopSync() - /** * Clear cache of the session. */ suspend fun clearCache() - /** - * This method allows to listen the sync state. - * @return a [LiveData] of [SyncState]. - */ - fun getSyncStateLive(): LiveData<SyncState> - - /** - * This method returns the current sync state. - * @return the current [SyncState]. - */ - fun getSyncState(): SyncState - - /** - * This method returns a flow of SyncResponse. New value will be pushed through the sync thread. - */ - fun syncFlow(): SharedFlow<SyncResponse> - - /** - * This methods return true if an initial sync has been processed. - */ - fun hasAlreadySynced(): Boolean - /** * This method allow to close a session. It does stop some services. */ @@ -247,9 +195,9 @@ interface Session { fun termsService(): TermsService /** - * Returns the SyncStatusService associated with the session. + * Returns the SyncService associated with the session. */ - fun syncStatusService(): SyncStatusService + fun syncService(): SyncService /** * Returns the SecureStorageService associated with the session. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt index 1f28dbd8afbef2c21b0e9aaee1d080c44b4ae3a9..e3d52adfc58da34c9825536ebeaab226e5ea32a0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/account/AccountService.kt @@ -27,8 +27,10 @@ interface AccountService { * @param password Current password. * @param newPassword New password */ - suspend fun changePassword(password: String, - newPassword: String) + suspend fun changePassword( + password: String, + newPassword: String + ) /** * Deactivate the account. @@ -46,6 +48,8 @@ interface AccountService { * an incomplete view of conversations * @param userInteractiveAuthInterceptor see [UserInteractiveAuthInterceptor] */ - suspend fun deactivateAccount(eraseAllData: Boolean, - userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) + suspend fun deactivateAccount( + eraseAllData: Boolean, + userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor + ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt index e13f7310e05696cecfa81c396f8357a5266d67ec..c87ac3c8218cdebab5928d9cf0ecc3613ea6eef2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt @@ -91,10 +91,12 @@ interface MxCall : MxCallDetail { * Send a m.call.replaces event to initiate call transfer. * See [org.matrix.android.sdk.api.session.room.model.call.CallReplacesContent] for documentation about the parameters */ - suspend fun transfer(targetUserId: String, - targetRoomId: String?, - createCallId: String?, - awaitCallId: String?) + suspend fun transfer( + targetUserId: String, + targetRoomId: String?, + createCallId: String?, + awaitCallId: String? + ) fun addListener(listener: StateListener) fun removeListener(listener: StateListener) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUrlResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUrlResolver.kt index e59e676ed9587f2670bbce0db540e7e5011a34ad..20f977e86e90bfd0293661076a268d722a960478 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUrlResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUrlResolver.kt @@ -36,7 +36,7 @@ interface ContentUrlResolver { /** * Get the actual URL for accessing the full-size image of a Matrix media content URI. * - * @param contentUrl the Matrix media content URI (in the form of "mxc://..."). + * @param contentUrl the Matrix media content URI (in the form of "mxc://..."). * @return the URL to access the described resource, or null if the url is invalid. */ fun resolveFullSize(contentUrl: String?): String? @@ -44,7 +44,7 @@ interface ContentUrlResolver { /** * Get the ResolvedMethod to download a URL. * - * @param contentUrl the Matrix media content URI (in the form of "mxc://..."). + * @param contentUrl the Matrix media content URI (in the form of "mxc://..."). * @param elementToDecrypt Encryption data may be required if you use a content scanner * @return the Method to access resource, or null if invalid */ @@ -54,9 +54,9 @@ interface ContentUrlResolver { * Get the actual URL for accessing the thumbnail image of a given Matrix media content URI. * * @param contentUrl the Matrix media content URI (in the form of "mxc://..."). - * @param width the desired width - * @param height the desired height - * @param method the desired method (METHOD_CROP or METHOD_SCALE) + * @param width the desired width + * @param height the desired height + * @param method the desired method (METHOD_CROP or METHOD_SCALE) * @return the URL to access the described resource, or null if the url is invalid. */ fun resolveThumbnail(contentUrl: String?, width: Int, height: Int, method: ThumbnailMethod): String? diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerService.kt index 7a85a89058a8ad011b4c68cea1248f2d7eaa1b34..22250628d5579dc7a7737b5dad4ec85577d27fa2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/contentscanner/ContentScannerService.kt @@ -33,7 +33,7 @@ interface ContentScannerService { /** * Get the current public curve25519 key that the AV server is advertising. - * @param callback on success callback containing the server public key + * @param forceDownload true to force the SDK to download again the server public key */ suspend fun getServerPublicKey(forceDownload: Boolean = false): String? suspend fun getScanResultForAttachment(mxcUrl: String, fileInfo: ElementToDecrypt? = null): ScanStatusInfo diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index 35f3ab3162466745fb6c09ec19e33368d392cbf6..9cc87b6f718476c8b0ea5ee530926e9507688427 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -88,9 +88,11 @@ interface CryptoService { fun getDeviceTrackingStatus(userId: String): Int - suspend fun importRoomKeys(roomKeysAsArray: ByteArray, - password: String, - progressListener: ProgressListener?): ImportRoomKeysResult + suspend fun importRoomKeys( + roomKeysAsArray: ByteArray, + password: String, + progressListener: ProgressListener? + ): ImportRoomKeysResult suspend fun exportRoomKeys(password: String): ByteArray @@ -119,10 +121,12 @@ interface CryptoService { fun isRoomEncrypted(roomId: String): Boolean // TODO This could be removed from this interface - fun encryptEventContent(eventContent: Content, - eventType: String, - roomId: String, - callback: MatrixCallback<MXEncryptEventContentResult>) + fun encryptEventContent( + eventContent: Content, + eventType: String, + roomId: String, + callback: MatrixCallback<MXEncryptEventContentResult> + ) fun discardOutboundSession(roomId: String) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/MXCryptoError.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/MXCryptoError.kt index 0b5bbe3bbdb5f38e6fd818b5490e6b8850825b6d..94ee7ba403e06b15aa9e3b9a90b10681b98d816c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/MXCryptoError.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/MXCryptoError.kt @@ -25,12 +25,14 @@ import org.matrix.olm.OlmException */ sealed class MXCryptoError : Throwable() { - data class Base(val errorType: ErrorType, - val technicalMessage: String, - /** - * Describe the error with more details. - */ - val detailedErrorDescription: String? = null) : MXCryptoError() + data class Base( + val errorType: ErrorType, + val technicalMessage: String, + /** + * Describe the error with more details. + */ + val detailedErrorDescription: String? = null + ) : MXCryptoError() data class OlmError(val olmException: OlmException) : MXCryptoError() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/OutgoingKeyRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/OutgoingKeyRequest.kt index 855f17a34fff1d165893a2e92db43555a1d2f52f..7202be7a214bf42f1c3a91e6ca6f472e77f01609 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/OutgoingKeyRequest.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/OutgoingKeyRequest.kt @@ -26,7 +26,7 @@ data class RequestReply( ) sealed class RequestResult { - data class Success(val chainIndex: Int) : RequestResult() + data class Success(val chainIndex: Int) : RequestResult() data class Failure(val code: WithHeldCode) : RequestResult() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt index 5439389096bbd3cb6210f2c89d0509cd83562c05..69f314f76f435a84f9bd035414a4a607910758ad 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt @@ -37,14 +37,18 @@ interface CrossSigningService { * Initialize cross signing for this user. * Users needs to enter credentials */ - fun initializeCrossSigning(uiaInterceptor: UserInteractiveAuthInterceptor?, - callback: MatrixCallback<Unit>) + fun initializeCrossSigning( + uiaInterceptor: UserInteractiveAuthInterceptor?, + callback: MatrixCallback<Unit> + ) fun isCrossSigningInitialized(): Boolean = getMyCrossSigningKeys() != null - fun checkTrustFromPrivateKeys(masterKeyPrivateKey: String?, - uskKeyPrivateKey: String?, - sskPrivateKey: String?): UserTrustResult + fun checkTrustFromPrivateKeys( + masterKeyPrivateKey: String?, + uskKeyPrivateKey: String?, + sskPrivateKey: String? + ): UserTrustResult fun getUserCrossSigningKeys(otherUserId: String): MXCrossSigningInfo? @@ -60,20 +64,26 @@ interface CrossSigningService { fun allPrivateKeysKnown(): Boolean - fun trustUser(otherUserId: String, - callback: MatrixCallback<Unit>) + fun trustUser( + otherUserId: String, + callback: MatrixCallback<Unit> + ) fun markMyMasterKeyAsTrusted() /** * Sign one of your devices and upload the signature. */ - fun trustDevice(deviceId: String, - callback: MatrixCallback<Unit>) - - fun checkDeviceTrust(otherUserId: String, - otherDeviceId: String, - locallyTrusted: Boolean?): DeviceTrustResult + fun trustDevice( + deviceId: String, + callback: MatrixCallback<Unit> + ) + + fun checkDeviceTrust( + otherUserId: String, + otherDeviceId: String, + locallyTrusted: Boolean? + ): DeviceTrustResult // FIXME Those method do not have to be in the service fun onSecretMSKGossip(mskPrivateKey: String) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupLastVersionResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupLastVersionResult.kt index a7e985cea9764cdf5b72696e8861d42b67c3b79c..92510bb52e50ae3de24fa9085b85be5be897c04d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupLastVersionResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupLastVersionResult.kt @@ -24,5 +24,5 @@ sealed interface KeysBackupLastVersionResult { fun KeysBackupLastVersionResult.toKeysVersionResult(): KeysVersionResult? = when (this) { is KeysBackupLastVersionResult.KeysBackup -> keysVersionResult - KeysBackupLastVersionResult.NoKeysBackup -> null + KeysBackupLastVersionResult.NoKeysBackup -> null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt index 0d40490c3e6858a290d21c0937d828cb687ce1b1..8745003f9f59ae67574587535c340b9bf0847084 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt @@ -34,10 +34,12 @@ interface KeysBackupService { * Create a new keys backup version and enable it, using the information return from [prepareKeysBackupVersion]. * * @param keysBackupCreationInfo the info object from [prepareKeysBackupVersion]. - * @param callback Asynchronous callback + * @param callback Asynchronous callback */ - fun createKeysBackupVersion(keysBackupCreationInfo: MegolmBackupCreationInfo, - callback: MatrixCallback<KeysVersion>) + fun createKeysBackupVersion( + keysBackupCreationInfo: MegolmBackupCreationInfo, + callback: MatrixCallback<KeysVersion> + ) /** * Facility method to get the total number of locally stored keys. @@ -55,8 +57,10 @@ interface KeysBackupService { * @param progressListener the callback to follow the progress * @param callback the main callback */ - fun backupAllGroupSessions(progressListener: ProgressListener?, - callback: MatrixCallback<Unit>?) + fun backupAllGroupSessions( + progressListener: ProgressListener?, + callback: MatrixCallback<Unit>? + ) /** * Check trust on a key backup version. @@ -64,8 +68,10 @@ interface KeysBackupService { * @param keysBackupVersion the backup version to check. * @param callback block called when the operations completes. */ - fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult, - callback: MatrixCallback<KeysBackupVersionTrust>) + fun getKeysBackupTrust( + keysBackupVersion: KeysVersionResult, + callback: MatrixCallback<KeysBackupVersionTrust> + ) /** * Return the current progress of the backup. @@ -79,8 +85,10 @@ interface KeysBackupService { * @param version the backup version * @param callback */ - fun getVersion(version: String, - callback: MatrixCallback<KeysVersionResult?>) + fun getVersion( + version: String, + callback: MatrixCallback<KeysVersionResult?> + ) /** * This method fetches the last backup version on the server, then compare to the currently backup version use. @@ -114,19 +122,23 @@ interface KeysBackupService { * @param progressListener a progress listener, as generating private key from password may take a while * @param callback Asynchronous callback */ - fun prepareKeysBackupVersion(password: String?, - progressListener: ProgressListener?, - callback: MatrixCallback<MegolmBackupCreationInfo>) + fun prepareKeysBackupVersion( + password: String?, + progressListener: ProgressListener?, + callback: MatrixCallback<MegolmBackupCreationInfo> + ) /** * Delete a keys backup version. It will delete all backed up keys on the server, and the backup itself. * If we are backing up to this version. Backup will be stopped. * - * @param version the backup version to delete. + * @param version the backup version to delete. * @param callback Asynchronous callback */ - fun deleteBackup(version: String, - callback: MatrixCallback<Unit>?) + fun deleteBackup( + version: String, + callback: MatrixCallback<Unit>? + ) /** * Ask if the backup on the server contains keys that we may do not have locally. @@ -142,9 +154,11 @@ interface KeysBackupService { * @param trust the trust to set to the keys backup. * @param callback block called when the operations completes. */ - fun trustKeysBackupVersion(keysBackupVersion: KeysVersionResult, - trust: Boolean, - callback: MatrixCallback<Unit>) + fun trustKeysBackupVersion( + keysBackupVersion: KeysVersionResult, + trust: Boolean, + callback: MatrixCallback<Unit> + ) /** * Set trust on a keys backup version. @@ -153,9 +167,11 @@ interface KeysBackupService { * @param recoveryKey the recovery key to challenge with the key backup public key. * @param callback block called when the operations completes. */ - fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult, - recoveryKey: String, - callback: MatrixCallback<Unit>) + fun trustKeysBackupVersionWithRecoveryKey( + keysBackupVersion: KeysVersionResult, + recoveryKey: String, + callback: MatrixCallback<Unit> + ) /** * Set trust on a keys backup version. @@ -164,27 +180,30 @@ interface KeysBackupService { * @param password the pass phrase to challenge with the keyBackupVersion public key. * @param callback block called when the operations completes. */ - fun trustKeysBackupVersionWithPassphrase(keysBackupVersion: KeysVersionResult, - password: String, - callback: MatrixCallback<Unit>) - - fun onSecretKeyGossip(secret: String) + fun trustKeysBackupVersionWithPassphrase( + keysBackupVersion: KeysVersionResult, + password: String, + callback: MatrixCallback<Unit> + ) /** * Restore a backup with a recovery key from a given backup version stored on the homeserver. * - * @param keysVersionResult the backup version to restore from. - * @param recoveryKey the recovery key to decrypt the retrieved backup. - * @param roomId the id of the room to get backup data from. - * @param sessionId the id of the session to restore. + * @param keysVersionResult the backup version to restore from. + * @param recoveryKey the recovery key to decrypt the retrieved backup. + * @param roomId the id of the room to get backup data from. + * @param sessionId the id of the session to restore. * @param stepProgressListener the step progress listener - * @param callback Callback. It provides the number of found keys and the number of successfully imported keys. + * @param callback Callback. It provides the number of found keys and the number of successfully imported keys. */ - fun restoreKeysWithRecoveryKey(keysVersionResult: KeysVersionResult, - recoveryKey: String, roomId: String?, - sessionId: String?, - stepProgressListener: StepProgressListener?, - callback: MatrixCallback<ImportRoomKeysResult>) + fun restoreKeysWithRecoveryKey( + keysVersionResult: KeysVersionResult, + recoveryKey: String, + roomId: String?, + sessionId: String?, + stepProgressListener: StepProgressListener?, + callback: MatrixCallback<ImportRoomKeysResult> + ) /** * Restore a backup with a password from a given backup version stored on the homeserver. @@ -196,18 +215,23 @@ interface KeysBackupService { * @param stepProgressListener the step progress listener * @param callback Callback. It provides the number of found keys and the number of successfully imported keys. */ - fun restoreKeyBackupWithPassword(keysBackupVersion: KeysVersionResult, - password: String, - roomId: String?, - sessionId: String?, - stepProgressListener: StepProgressListener?, - callback: MatrixCallback<ImportRoomKeysResult>) + fun restoreKeyBackupWithPassword( + keysBackupVersion: KeysVersionResult, + password: String, + roomId: String?, + sessionId: String?, + stepProgressListener: StepProgressListener?, + callback: MatrixCallback<ImportRoomKeysResult> + ) val keysBackupVersion: KeysVersionResult? + val currentBackupVersion: String? - val isEnabled: Boolean - val isStucked: Boolean - val state: KeysBackupState + get() = keysBackupVersion?.version + + fun isEnabled(): Boolean + fun isStuck(): Boolean + fun getState(): KeysBackupState // For gossiping fun saveBackupRecoveryKey(recoveryKey: String?, version: String?) @@ -215,8 +239,10 @@ interface KeysBackupService { fun isValidRecoveryKeyForCurrentVersion(recoveryKey: String, callback: MatrixCallback<Boolean>) - fun computePrivateKey(passphrase: String, - privateKeySalt: String, - privateKeyIterations: Int, - progressListener: ProgressListener): ByteArray + fun computePrivateKey( + passphrase: String, + privateKeySalt: String, + privateKeyIterations: Int, + progressListener: ProgressListener + ): ByteArray } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupState.kt index a4cc133398203ae4af23b47cc2d8343e4afd09db..a867d573de59cf77bc15bb5872ee87714a984913 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupState.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupState.kt @@ -51,33 +51,51 @@ package org.matrix.android.sdk.api.session.crypto.keysbackup * </pre> */ enum class KeysBackupState { - // Need to check the current backup version on the homeserver + /** + * Need to check the current backup version on the homeserver. + */ Unknown, - // Checking if backup is enabled on homeserver + /** + * Checking if backup is enabled on homeserver. + */ CheckingBackUpOnHomeserver, - // Backup has been stopped because a new backup version has been detected on the homeserver + /** + * Backup has been stopped because a new backup version has been detected on the homeserver. + */ WrongBackUpVersion, - // Backup from this device is not enabled + /** + * Backup from this device is not enabled. + */ Disabled, - // There is a backup available on the homeserver but it is not trusted. - // It is not trusted because the signature is invalid or the device that created it is not verified - // Use [KeysBackup.getKeysBackupTrust()] to get trust details. - // Consequently, the backup from this device is not enabled. + /** + * There is a backup available on the homeserver but it is not trusted. + * It is not trusted because the signature is invalid or the device that created it is not verified. + * Use [KeysBackup.getKeysBackupTrust()] to get trust details. + * Consequently, the backup from this device is not enabled. + */ NotTrusted, - // Backup is being enabled: the backup version is being created on the homeserver + /** + * Backup is being enabled: the backup version is being created on the homeserver. + */ Enabling, - // Backup is enabled and ready to send backup to the homeserver + /** + * Backup is enabled and ready to send backup to the homeserver. + */ ReadyToBackUp, - // e2e keys are going to be sent to the homeserver + /** + * e2e keys are going to be sent to the homeserver. + */ WillBackUp, - // e2e keys are being sent to the homeserver + /** + * e2e keys are being sent to the homeserver. + */ BackingUp } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupVersionTrustSignature.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupVersionTrustSignature.kt index 7127c8d3f45063112dbedd822a5e9809b81e45ac..afbf45ac702963c23d8a89dd5cb5ddaa126f9335 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupVersionTrustSignature.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupVersionTrustSignature.kt @@ -40,7 +40,8 @@ sealed class KeysBackupVersionTrustSignature { /** * Flag to indicate the signature from this device is valid. */ - val valid: Boolean) : KeysBackupVersionTrustSignature() + val valid: Boolean + ) : KeysBackupVersionTrustSignature() data class UserSignature( val keyId: String?, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingRoomKeyRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingRoomKeyRequest.kt index 0c19d275cc375a4f47206fdaf0dc9966ce858d61..4ff196dd07d4d22de995dd66b41586e0bfa9d1a0 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingRoomKeyRequest.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/IncomingRoomKeyRequest.kt @@ -48,8 +48,7 @@ data class IncomingRoomKeyRequest( /** * Factory. * - * @param event the event - * @param currentTimeMillis the current time in milliseconds + * @param trail the AuditTrail data */ fun fromEvent(trail: AuditTrail): IncomingRoomKeyRequest? { return trail diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXUsersDevicesMap.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXUsersDevicesMap.kt index 744fe74d0da947bf5b0b2d141cf340f4a8b6e6e9..736ae6b318d0919c05207034da1605f2bdf0222d 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXUsersDevicesMap.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXUsersDevicesMap.kt @@ -46,8 +46,8 @@ class MXUsersDevicesMap<E> { /** * Provides the object for a device id and a user Id. * + * @param userId the user id * @param deviceId the device id - * @param userId the object id * @return the object */ fun getObject(userId: String?, deviceId: String?): E? { @@ -59,9 +59,9 @@ class MXUsersDevicesMap<E> { /** * Set an object for a dedicated user Id and device Id. * - * @param userId the user Id + * @param userId the user Id * @param deviceId the device id - * @param o the object to set + * @param o the object to set */ fun setObject(userId: String?, deviceId: String?, o: E?) { if (null != o && userId?.isNotBlank() == true && deviceId?.isNotBlank() == true) { @@ -73,8 +73,8 @@ class MXUsersDevicesMap<E> { /** * Defines the objects map for a user Id. * + * @param userId the user id * @param objectsPerDevices the objects maps - * @param userId the user id */ fun setObjects(userId: String?, objectsPerDevices: Map<String, E>?) { if (!userId.isNullOrBlank()) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomEncryptionTrustLevel.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomEncryptionTrustLevel.kt index 68c7496d58d65aa7d1a5a759b50b3fd9b114f368..78724819a3f298bc78bc421fa869263ea884d78e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomEncryptionTrustLevel.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/RoomEncryptionTrustLevel.kt @@ -20,15 +20,23 @@ package org.matrix.android.sdk.api.session.crypto.model * RoomEncryptionTrustLevel represents the trust level in an encrypted room. */ enum class RoomEncryptionTrustLevel { - // No one in the room has been verified -> Black shield + /** + * No one in the room has been verified -> Black shield. + */ Default, - // There are one or more device un-verified -> the app should display a red shield + /** + * There are one or more device un-verified -> the app should display a red shield. + */ Warning, - // All devices in the room are verified -> the app should display a green shield + /** + * All devices in the room are verified -> the app should display a green shield. + */ Trusted, - // e2e is active but with an unsupported algorithm + /** + * e2e is active but with an unsupported algorithm. + */ E2EWithUnsupportedAlgorithm } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/CancelCode.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/CancelCode.kt index 5a025f37e151459b3750c3a9ee96a2cb25ba26fb..e4716d7794ba7753e89781cd1c8d469f7bac4b17 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/CancelCode.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/CancelCode.kt @@ -28,7 +28,8 @@ enum class CancelCode(val value: String, val humanReadable: String) { MismatchedKeys("m.key_mismatch", "Key mismatch"), UserError("m.user_error", "User error"), MismatchedUser("m.user_mismatch", "User mismatch"), - QrCodeInvalid("m.qr_code.invalid", "Invalid QR code") + QrCodeInvalid("m.qr_code.invalid", "Invalid QR code"), + AcceptedByAnotherDevice("m.accepted", "Verification request accepted by another device") } fun safeValueOf(code: String?): CancelCode { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/EmojiRepresentation.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/EmojiRepresentation.kt index 2c1bf9ff4df3fd1167c9d6ba95e236645a8d8c79..5402471e466d3ccea3f3e802641f525c696e9632 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/EmojiRepresentation.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/EmojiRepresentation.kt @@ -19,7 +19,8 @@ package org.matrix.android.sdk.api.session.crypto.verification import androidx.annotation.DrawableRes import androidx.annotation.StringRes -data class EmojiRepresentation(val emoji: String, - @StringRes val nameResId: Int, - @DrawableRes val drawableRes: Int? = null +data class EmojiRepresentation( + val emoji: String, + @StringRes val nameResId: Int, + @DrawableRes val drawableRes: Int? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationMethod.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationMethod.kt index f2de2c4b47ed2fedd920021d9dcd21e5d9a6a9ee..0ab47a2ecdedadd137d7578d8b2f7e0c2f8b06bb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationMethod.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationMethod.kt @@ -20,12 +20,18 @@ package org.matrix.android.sdk.api.session.crypto.verification * Verification methods. */ enum class VerificationMethod { - // Use it when your application supports the SAS verification method + /** + * Use it when your application supports the SAS verification method. + */ SAS, - // Use it if your application is able to display QR codes + /** + * Use it if your application is able to display QR codes. + */ QR_CODE_SHOW, - // Use it if your application is able to scan QR codes + /** + * Use it if your application is able to scan QR codes. + */ QR_CODE_SCAN } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt index 321ec7309403b5a961b96a7f26ae85e214b32fb2..ee93f149927bbfeccce33e2b3da083ced6e56439 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationService.kt @@ -46,54 +46,68 @@ interface VerificationService { fun getExistingVerificationRequestInRoom(roomId: String, tid: String?): PendingVerificationRequest? - fun beginKeyVerification(method: VerificationMethod, - otherUserId: String, - otherDeviceId: String, - transactionId: String?): String? + fun beginKeyVerification( + method: VerificationMethod, + otherUserId: String, + otherDeviceId: String, + transactionId: String? + ): String? /** * Request key verification with another user via room events (instead of the to-device API). */ - fun requestKeyVerificationInDMs(methods: List<VerificationMethod>, - otherUserId: String, - roomId: String, - localId: String? = LocalEcho.createLocalEchoId()): PendingVerificationRequest + fun requestKeyVerificationInDMs( + methods: List<VerificationMethod>, + otherUserId: String, + roomId: String, + localId: String? = LocalEcho.createLocalEchoId() + ): PendingVerificationRequest fun cancelVerificationRequest(request: PendingVerificationRequest) /** * Request a key verification from another user using toDevice events. */ - fun requestKeyVerification(methods: List<VerificationMethod>, - otherUserId: String, - otherDevices: List<String>?): PendingVerificationRequest - - fun declineVerificationRequestInDMs(otherUserId: String, - transactionId: String, - roomId: String) + fun requestKeyVerification( + methods: List<VerificationMethod>, + otherUserId: String, + otherDevices: List<String>? + ): PendingVerificationRequest + + fun declineVerificationRequestInDMs( + otherUserId: String, + transactionId: String, + roomId: String + ) // Only SAS method is supported for the moment // TODO Parameter otherDeviceId should be removed in this case - fun beginKeyVerificationInDMs(method: VerificationMethod, - transactionId: String, - roomId: String, - otherUserId: String, - otherDeviceId: String): String + fun beginKeyVerificationInDMs( + method: VerificationMethod, + transactionId: String, + roomId: String, + otherUserId: String, + otherDeviceId: String + ): String /** * Returns false if the request is unknown. */ - fun readyPendingVerificationInDMs(methods: List<VerificationMethod>, - otherUserId: String, - roomId: String, - transactionId: String): Boolean + fun readyPendingVerificationInDMs( + methods: List<VerificationMethod>, + otherUserId: String, + roomId: String, + transactionId: String + ): Boolean /** * Returns false if the request is unknown. */ - fun readyPendingVerification(methods: List<VerificationMethod>, - otherUserId: String, - transactionId: String): Boolean + fun readyPendingVerification( + methods: List<VerificationMethod>, + otherUserId: String, + transactionId: String + ): Boolean interface Listener { /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTxState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTxState.kt index 39de2cc7120d1177f429ec2035e776785128cbb3..30e4c6693753f00eb840227218bc126604c67664 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTxState.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTxState.kt @@ -17,10 +17,14 @@ package org.matrix.android.sdk.api.session.crypto.verification sealed class VerificationTxState { - // Uninitialized state + /** + * Uninitialized state. + */ object None : VerificationTxState() - // Specific for SAS + /** + * Specific for SAS. + */ abstract class VerificationSasTxState : VerificationTxState() object SendingStart : VerificationSasTxState() @@ -38,18 +42,26 @@ sealed class VerificationTxState { object MacSent : VerificationSasTxState() object Verifying : VerificationSasTxState() - // Specific for QR code + /** + * Specific for QR code. + */ abstract class VerificationQrTxState : VerificationTxState() - // Will be used to ask the user if the other user has correctly scanned + /** + * Will be used to ask the user if the other user has correctly scanned. + */ object QrScannedByOther : VerificationQrTxState() object WaitingOtherReciprocateConfirm : VerificationQrTxState() - // Terminal states + /** + * Terminal states. + */ abstract class TerminalTxState : VerificationTxState() object Verified : TerminalTxState() - // Cancelled by me or by other + /** + * Cancelled by me or by other. + */ data class Cancelled(val cancelCode: CancelCode, val byMe: Boolean) : TerminalTxState() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/EventService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/EventService.kt index 297f277497f13e48f59392b00a08c55eaaab9b98..7f275bf95291e8c968619b9b820a864859e49080 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/EventService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/EventService.kt @@ -24,6 +24,8 @@ interface EventService { * Ask the homeserver for an event content. The SDK will try to decrypt it if it is possible * The result will not be stored into cache */ - suspend fun getEvent(roomId: String, - eventId: String): Event + suspend fun getEvent( + roomId: String, + eventId: String + ): Event } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt index 16bdbd3432bd5bfb1d67a999af754803ff361c0a..7f9ab4c6dd61faa8434ee462819570167dde7e09 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt @@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomMemberContent +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent @@ -211,13 +212,13 @@ data class Event( return when { isReplyRenderedInThread() || isQuote() -> ContentUtils.extractUsefulTextFromReply(text) - isFileMessage() -> "sent a file." - isAudioMessage() -> "sent an audio file." - isImageMessage() -> "sent an image." - isVideoMessage() -> "sent a video." - isSticker() -> "sent a sticker" - isPoll() -> getPollQuestion() ?: "created a poll." - else -> text + isFileMessage() -> "sent a file." + isAudioMessage() -> "sent an audio file." + isImageMessage() -> "sent an image." + isVideoMessage() -> "sent a video." + isSticker() -> "sent a sticker" + isPoll() -> getPollQuestion() ?: "created a poll." + else -> text } } @@ -317,35 +318,35 @@ fun Event.isTextMessage(): Boolean { MessageType.MSGTYPE_TEXT, MessageType.MSGTYPE_EMOTE, MessageType.MSGTYPE_NOTICE -> true - else -> false + else -> false } } fun Event.isImageMessage(): Boolean { return when (getMsgType()) { MessageType.MSGTYPE_IMAGE -> true - else -> false + else -> false } } fun Event.isVideoMessage(): Boolean { return when (getMsgType()) { MessageType.MSGTYPE_VIDEO -> true - else -> false + else -> false } } fun Event.isAudioMessage(): Boolean { return when (getMsgType()) { MessageType.MSGTYPE_AUDIO -> true - else -> false + else -> false } } fun Event.isFileMessage(): Boolean { return when (getMsgType()) { MessageType.MSGTYPE_FILE -> true - else -> false + else -> false } } @@ -355,14 +356,14 @@ fun Event.isAttachmentMessage(): Boolean { MessageType.MSGTYPE_AUDIO, MessageType.MSGTYPE_VIDEO, MessageType.MSGTYPE_FILE -> true - else -> false + else -> false } } fun Event.isLocationMessage(): Boolean { return when (getMsgType()) { MessageType.MSGTYPE_LOCATION -> true - else -> false + else -> false } } @@ -375,11 +376,11 @@ fun Event.getRelationContent(): RelationDefaultContent? { content.toModel<EncryptedEventContent>()?.relatesTo } else { content.toModel<MessageContent>()?.relatesTo ?: run { - // Special case to handle stickers, while there is only a local msgtype for stickers - if (getClearType() == EventType.STICKER) { - getClearContent().toModel<MessageStickerContent>()?.relatesTo - } else { - null + // Special cases when there is only a local msgtype for some event types + when (getClearType()) { + EventType.STICKER -> getClearContent().toModel<MessageStickerContent>()?.relatesTo + in EventType.BEACON_LOCATION_DATA -> getClearContent().toModel<MessageBeaconLocationDataContent>()?.relatesTo + else -> null } } } @@ -426,3 +427,6 @@ fun Event.getPollContent(): MessagePollContent? { fun Event.supportsNotification() = this.getClearType() in EventType.MESSAGE + EventType.POLL_START + EventType.STATE_ROOM_BEACON_INFO + +fun Event.isContentReportable() = + this.getClearType() in EventType.MESSAGE + EventType.STATE_ROOM_BEACON_INFO diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyWithHeldContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyWithHeldContent.kt index d58c3614a70af1f0ef522243c0595dcacc1b79d6..fb8b65c4f279c265e25d8627ef7619d00e473265 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyWithHeldContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/content/RoomKeyWithHeldContent.kt @@ -98,12 +98,12 @@ enum class WithHeldCode(val value: String) { companion object { fun fromCode(code: String?): WithHeldCode? { return when (code) { - BLACKLISTED.value -> BLACKLISTED - UNVERIFIED.value -> UNVERIFIED + BLACKLISTED.value -> BLACKLISTED + UNVERIFIED.value -> UNVERIFIED UNAUTHORISED.value -> UNAUTHORISED - UNAVAILABLE.value -> UNAVAILABLE - NO_OLM.value -> NO_OLM - else -> null + UNAVAILABLE.value -> UNAVAILABLE + NO_OLM.value -> NO_OLM + else -> null } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/FileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/FileService.kt index 84a99908268ecccf607f51473b7e9cb90ddea35b..ca6c889cb84506f5e0fe9b147437d6918e90ad63 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/FileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/file/FileService.kt @@ -33,7 +33,7 @@ interface FileService { /** * The original file is in cache, but the decrypted files can be deleted for security reason. * To decrypt the file again, call [downloadFile], the encrypted file will not be downloaded again - * @param decryptedFileInCache true if the decrypted file is available. Always true for clear files. + * @property decryptedFileInCache true if the decrypted file is available. Always true for clear files. */ data class InCache(val decryptedFileInCache: Boolean) : FileState() object Downloading : FileState() @@ -44,10 +44,12 @@ interface FileService { * Download a file if necessary and ensure that if the file is encrypted, the file is decrypted. * Result will be a decrypted file, stored in the cache folder. url parameter will be used to create unique filename to avoid name collision. */ - suspend fun downloadFile(fileName: String, - mimeType: String?, - url: String?, - elementToDecrypt: ElementToDecrypt?): File + suspend fun downloadFile( + fileName: String, + mimeType: String?, + url: String?, + elementToDecrypt: ElementToDecrypt? + ): File suspend fun downloadFile(messageContent: MessageWithAttachmentContent): File = downloadFile( @@ -57,10 +59,11 @@ interface FileService { elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt() ) - fun isFileInCache(mxcUrl: String?, - fileName: String, - mimeType: String?, - elementToDecrypt: ElementToDecrypt? + fun isFileInCache( + mxcUrl: String?, + fileName: String, + mimeType: String?, + elementToDecrypt: ElementToDecrypt? ): Boolean fun isFileInCache(messageContent: MessageWithAttachmentContent) = @@ -75,10 +78,12 @@ interface FileService { * Use this URI and pass it to intent using flag Intent.FLAG_GRANT_READ_URI_PERMISSION * (if not other app won't be able to access it). */ - fun getTemporarySharableURI(mxcUrl: String?, - fileName: String, - mimeType: String?, - elementToDecrypt: ElementToDecrypt?): Uri? + fun getTemporarySharableURI( + mxcUrl: String?, + fileName: String, + mimeType: String?, + elementToDecrypt: ElementToDecrypt? + ): Uri? fun getTemporarySharableURI(messageContent: MessageWithAttachmentContent): Uri? = getTemporarySharableURI( @@ -92,10 +97,12 @@ interface FileService { * Get information on the given file. * Mimetype should be the same one as passed to downloadFile (limitation for now) */ - fun fileState(mxcUrl: String?, - fileName: String, - mimeType: String?, - elementToDecrypt: ElementToDecrypt?): FileState + fun fileState( + mxcUrl: String?, + fileName: String, + mimeType: String?, + elementToDecrypt: ElementToDecrypt? + ): FileState fun fileState(messageContent: MessageWithAttachmentContent): FileState = fileState( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt index 5b06fdacae2c938fa9126c3a398ac94d488d309e..c78fb9cf7928c372435b2930d6d0b8f3f9be3eda 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt @@ -81,13 +81,13 @@ data class HomeServerCapabilities( val versionCap = roomVersions.supportedVersion.firstOrNull { it.version == preferred } return when { - versionCap == null -> { + versionCap == null -> { RoomCapabilitySupport.UNKNOWN } versionCap.status == RoomVersionStatus.STABLE -> { RoomCapabilitySupport.SUPPORTED } - else -> { + else -> { RoomCapabilitySupport.SUPPORTED_UNSTABLE } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt index c03b42e6c894037487126dc7e7b133be156ace9b..2fb35d38e32a6b44155495961016d02069091f4d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt @@ -74,6 +74,7 @@ interface IdentityService { /** * Submit the code that the identity server has sent to the user (in email or SMS). * Once successful, you will have to call [finalizeBindThreePid] + * @param threePid the three pid * @param code the code sent to the user */ suspend fun submitValidationToken(threePid: ThreePid, code: String) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt index 42d777849b80c8eb64728ce4b7182fe4dfbf7028..6bcf576824e57d896bff863be83dd64bf43a0a9c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/ThreePid.kt @@ -27,7 +27,7 @@ sealed class ThreePid(open val value: String) { internal fun ThreePid.toMedium(): String { return when (this) { - is ThreePid.Email -> ThirdPartyIdentifier.MEDIUM_EMAIL + is ThreePid.Email -> ThirdPartyIdentifier.MEDIUM_EMAIL is ThreePid.Msisdn -> ThirdPartyIdentifier.MEDIUM_MSISDN } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/SyncStatusService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/SyncStatusService.kt deleted file mode 100644 index 7006e117512bf4405c7f17e52f2334f2c52f57a3..0000000000000000000000000000000000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/SyncStatusService.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2020 The Matrix.org Foundation C.I.C. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.matrix.android.sdk.api.session.initsync - -import androidx.lifecycle.LiveData - -interface SyncStatusService { - - fun getSyncStatusLive(): LiveData<Status> - - sealed class Status { - /** - * For initial sync. - */ - abstract class InitialSyncStatus : Status() - - object Idle : InitialSyncStatus() - data class InitialSyncProgressing( - val initSyncStep: InitSyncStep, - val percentProgress: Int = 0 - ) : InitialSyncStatus() - - /** - * For incremental sync. - */ - abstract class IncrementalSyncStatus : Status() - - object IncrementalSyncIdle : IncrementalSyncStatus() - data class IncrementalSyncParsing( - val rooms: Int, - val toDevice: Int - ) : IncrementalSyncStatus() - - object IncrementalSyncError : IncrementalSyncStatus() - object IncrementalSyncDone : IncrementalSyncStatus() - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/integrationmanager/IntegrationManagerService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/integrationmanager/IntegrationManagerService.kt index 60af93888e65063f3ce1cf03f4bdb4164459d52a..5b15a0cb1368f5b7eff1643d81c089f1e7ab1e38 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/integrationmanager/IntegrationManagerService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/integrationmanager/IntegrationManagerService.kt @@ -99,6 +99,7 @@ interface IntegrationManagerService { * Offers to allow or disallow a native widget domain. * @param widgetType the widget type to check for * @param domain the domain to check for + * @param allowed true or false */ suspend fun setNativeWidgetDomainAllowed(widgetType: String, domain: String, allowed: Boolean) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixLinkify.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixLinkify.kt index c5d919407aecbf50ea6a03239c0a07266a520c7d..c428e40203000b4a998bc909bf3f63cc6d6a2fe7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixLinkify.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixLinkify.kt @@ -29,6 +29,7 @@ object MatrixLinkify { * Find the matrix spans i.e matrix id , user id ... to display them as URL. * * @param spannable the text in which the matrix items has to be clickable. + * @param callback listener to be notified when the span is clicked */ @Suppress("UNUSED_PARAMETER") fun addLinks(spannable: Spannable, callback: MatrixPermalinkSpan.Callback?): Boolean { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixPermalinkSpan.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixPermalinkSpan.kt index 2f8f5f99a53e7cbb5792485b04c9946d27372893..9c71c081beda14ba4a5037f8c7bb0895e04bc11d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixPermalinkSpan.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixPermalinkSpan.kt @@ -22,11 +22,13 @@ import org.matrix.android.sdk.api.session.permalinks.MatrixPermalinkSpan.Callbac /** * This MatrixPermalinkSpan is a clickable span which use a [Callback] to communicate back. - * @param url the permalink url tied to the span - * @param callback the callback to use. + * @property url the permalink url tied to the span + * @property callback the callback to use. */ -class MatrixPermalinkSpan(private val url: String, - private val callback: Callback? = null) : ClickableSpan() { +class MatrixPermalinkSpan( + private val url: String, + private val callback: Callback? = null +) : ClickableSpan() { interface Callback { fun onUrlClicked(url: String) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixToConverter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixToConverter.kt index a904e89681a554a44a62921860f2f2f8fb962a1d..c418b59df41bc04c8143ef4d6037c52b44b7353d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixToConverter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/MatrixToConverter.kt @@ -38,12 +38,12 @@ object MatrixToConverter { // URL is already a matrix.to uriString.startsWith(PermalinkService.MATRIX_TO_URL_BASE) -> uri // Web or client url - SUPPORTED_PATHS.any { it in uriString } -> { + SUPPORTED_PATHS.any { it in uriString } -> { val path = SUPPORTED_PATHS.first { it in uriString } Uri.parse(PermalinkService.MATRIX_TO_URL_BASE + uriString.substringAfter(path)) } // URL is not supported - else -> null + else -> null } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt index 9d078dc4b243e1f9ff0b5407a22c6f29364e8198..0168b7ac3ab6e9679916da9ecf416a0fdf5205f4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt @@ -67,10 +67,10 @@ object PermalinkParser { val identifier = params.getOrNull(0) val extraParameter = params.getOrNull(1) return when { - identifier.isNullOrEmpty() -> PermalinkData.FallbackLink(uri) - MatrixPatterns.isUserId(identifier) -> PermalinkData.UserLink(userId = identifier) - MatrixPatterns.isGroupId(identifier) -> PermalinkData.GroupLink(groupId = identifier) - MatrixPatterns.isRoomId(identifier) -> { + identifier.isNullOrEmpty() -> PermalinkData.FallbackLink(uri) + MatrixPatterns.isUserId(identifier) -> PermalinkData.UserLink(userId = identifier) + MatrixPatterns.isGroupId(identifier) -> PermalinkData.GroupLink(groupId = identifier) + MatrixPatterns.isRoomId(identifier) -> { handleRoomIdCase(fragment, identifier, matrixToUri, extraParameter, viaQueryParameters) } MatrixPatterns.isRoomAlias(identifier) -> { @@ -81,7 +81,7 @@ object PermalinkParser { viaParameters = viaQueryParameters ) } - else -> PermalinkData.FallbackLink(uri) + else -> PermalinkData.FallbackLink(uri) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt index b49b80df099c87206773cf54898bc717f97b7c98..1788bf7bd2466d3ac7a53bca0d16e319c783bec9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt @@ -60,6 +60,7 @@ interface PermalinkService { * Creates a permalink for a roomId, including the via parameters. * * @param roomId the room id + * @param viaServers the via parameter * @param forceMatrixTo whether we should force using matrix.to base URL * * @return the permalink, or null in case of error @@ -70,7 +71,7 @@ interface PermalinkService { * Creates a permalink for an event. If you have an event you can use [createPermalink] * Ex: "https://matrix.to/#/!nbzmcXAqpxBXjAdgoX:matrix.org/$1531497316352799BevdV:matrix.org?via=matrix.org" * - * @param roomId the id of the room + * @param roomId the id of the room * @param eventId the id of the event * @param forceMatrixTo whether we should force using matrix.to base URL * @@ -90,7 +91,7 @@ interface PermalinkService { * Creates a HTML or Markdown mention span template. Can be used to replace a mention with a permalink to mentioned user. * Ex: "<a href=\"https://matrix.to/#/%1\$s\">%2\$s</a>" or "[%2\$s](https://matrix.to/#/%1\$s)" * - * @param type: type of template to create + * @param type type of template to create * @param forceMatrixTo whether we should force using matrix.to base URL * * @return the created template diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt index 095f2ef7c2c9058f463c4b361a73eb05e76fb9fa..4c00c764593c5c1f93fe46583d013e2b083ab62e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt @@ -107,8 +107,10 @@ interface ProfileService { /** * Finalize adding a 3Pids. Call this method once the user has validated that he owns the ThreePid. */ - suspend fun finalizeAddingThreePid(threePid: ThreePid, - userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) + suspend fun finalizeAddingThreePid( + threePid: ThreePid, + userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor + ) /** * Cancel adding a threepid. It will remove locally stored data about this ThreePid. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/HttpPusher.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/HttpPusher.kt new file mode 100644 index 0000000000000000000000000000000000000000..1ae23e2b7015c7dd58163ab0dad7a67fc489df37 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/HttpPusher.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.pushers + +data class HttpPusher( + /** + * This is a unique identifier for this pusher. The value you should use for + * this is the routing or destination address information for the notification, + * for example, the APNS token for APNS or the Registration ID for GCM. If your + * notification client has no such concept, use any unique identifier. Max length, 512 chars. + */ + val pushkey: String, + + /** + * The application id + * This is a reverse-DNS style identifier for the application. It is recommended + * that this end with the platform, such that different platform versions get + * different app identifiers. Max length, 64 chars. + */ + val appId: String, + + /** + * This string determines which set of device specific rules this pusher executes. + */ + val profileTag: String, + + /** + * The preferred language for receiving notifications (e.g. "en" or "en-US"). + */ + val lang: String, + + /** + * A human readable string that will allow the user to identify what application owns this pusher. + */ + val appDisplayName: String, + + /** + * A human readable string that will allow the user to identify what device owns this pusher. + */ + val deviceDisplayName: String, + + /** + * The URL to use to send notifications to. MUST be an HTTPS URL with a path of /_matrix/push/v1/notify. + */ + val url: String, + + /** + * If true, the homeserver should add another pusher with the given pushkey and App ID in addition + * to any others with different user IDs. Otherwise, the homeserver must remove any other pushers + * with the same App ID and pushkey for different users. + */ + val append: Boolean, + + /** + * true to limit the push content to only id and not message content + * Ref: https://matrix.org/docs/spec/push_gateway/r0.1.1#homeserver-behaviour + */ + val withEventIdOnly: Boolean +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt index 5f9857eb2fbb60a19848ead18578bb8ae454675f..d7958ea3cdd0f6e44c1ab00577687fb3efa836ed 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt @@ -47,23 +47,25 @@ interface PushersService { * Add a new Email pusher. * Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-pushers-set * - * @param email The email address to send notifications to. - * @param lang The preferred language for receiving notifications (e.g. "en" or "en-US"). - * @param emailBranding The branding placeholder to include in the email communications. - * @param appDisplayName A human readable string that will allow the user to identify what application owns this pusher. + * @param email The email address to send notifications to. + * @param lang The preferred language for receiving notifications (e.g. "en" or "en-US"). + * @param emailBranding The branding placeholder to include in the email communications. + * @param appDisplayName A human readable string that will allow the user to identify what application owns this pusher. * @param deviceDisplayName A human readable string that will allow the user to identify what device owns this pusher. - * @param append If true, the homeserver should add another pusher with the given pushkey and App ID in addition + * @param append If true, the homeserver should add another pusher with the given pushkey and App ID in addition * to any others with different user IDs. Otherwise, the homeserver must remove any other pushers * with the same App ID and pushkey for different users. Typically We always want to append for * email pushers since we don't want to stop other accounts notifying to the same email address. * @throws [InvalidParameterException] if a parameter is not correct */ - suspend fun addEmailPusher(email: String, - lang: String, - emailBranding: String, - appDisplayName: String, - deviceDisplayName: String, - append: Boolean = true) + suspend fun addEmailPusher( + email: String, + lang: String, + emailBranding: String, + appDisplayName: String, + deviceDisplayName: String, + append: Boolean = true + ) /** * Directly ask the push gateway to send a push to this device. @@ -75,10 +77,12 @@ interface PushersService { * @param pushkey the FCM token * @param eventId the eventId which will be sent in the Push message. Use a fake eventId. */ - suspend fun testPush(url: String, - appId: String, - pushkey: String, - eventId: String) + suspend fun testPush( + url: String, + appId: String, + pushkey: String, + eventId: String + ) /** * Remove a registered pusher. @@ -107,61 +111,4 @@ interface PushersService { * Get the current pushers. */ fun getPushers(): List<Pusher> - - data class HttpPusher( - - /** - * This is a unique identifier for this pusher. The value you should use for - * this is the routing or destination address information for the notification, - * for example, the APNS token for APNS or the Registration ID for GCM. If your - * notification client has no such concept, use any unique identifier. Max length, 512 chars. - */ - val pushkey: String, - - /** - * The application id - * This is a reverse-DNS style identifier for the application. It is recommended - * that this end with the platform, such that different platform versions get - * different app identifiers. Max length, 64 chars. - */ - val appId: String, - - /** - * This string determines which set of device specific rules this pusher executes. - */ - val profileTag: String, - - /** - * The preferred language for receiving notifications (e.g. "en" or "en-US"). - */ - val lang: String, - - /** - * A human readable string that will allow the user to identify what application owns this pusher. - */ - val appDisplayName: String, - - /** - * A human readable string that will allow the user to identify what device owns this pusher. - */ - val deviceDisplayName: String, - - /** - * The URL to use to send notifications to. MUST be an HTTPS URL with a path of /_matrix/push/v1/notify. - */ - val url: String, - - /** - * If true, the homeserver should add another pusher with the given pushkey and App ID in addition - * to any others with different user IDs. Otherwise, the homeserver must remove any other pushers - * with the same App ID and pushkey for different users. - */ - val append: Boolean, - - /** - * true to limit the push content to only id and not message content - * Ref: https://matrix.org/docs/spec/push_gateway/r0.1.1#homeserver-behaviour - */ - val withEventIdOnly: Boolean - ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt index 2b2930c1ba01022e4352c076647a3563ef1d532e..6122aae972e8a7b4bc88daaed1909f65077b79ed 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt @@ -71,15 +71,15 @@ sealed class Action { fun List<Action>.toJson(): List<Any> { return map { action -> when (action) { - is Action.Notify -> Action.ACTION_NOTIFY + is Action.Notify -> Action.ACTION_NOTIFY is Action.DoNotNotify -> Action.ACTION_DONT_NOTIFY - is Action.Sound -> { + is Action.Sound -> { mapOf( Action.ACTION_OBJECT_SET_TWEAK_KEY to Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND, Action.ACTION_OBJECT_VALUE_KEY to action.sound ) } - is Action.Highlight -> { + is Action.Highlight -> { mapOf( Action.ACTION_OBJECT_SET_TWEAK_KEY to Action.ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT, Action.ACTION_OBJECT_VALUE_KEY to action.highlight @@ -94,11 +94,11 @@ fun PushRule.getActions(): List<Action> { actions.forEach { actionStrOrObj -> when (actionStrOrObj) { - Action.ACTION_NOTIFY -> Action.Notify + Action.ACTION_NOTIFY -> Action.Notify Action.ACTION_DONT_NOTIFY -> Action.DoNotNotify - is Map<*, *> -> { + is Map<*, *> -> { when (actionStrOrObj[Action.ACTION_OBJECT_SET_TWEAK_KEY]) { - Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> { + Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> { (actionStrOrObj[Action.ACTION_OBJECT_VALUE_KEY] as? String)?.let { stringValue -> Action.Sound(stringValue) } @@ -112,13 +112,13 @@ fun PushRule.getActions(): List<Action> { // When the value is not there, default is true, says the spec ?: Action.Highlight(true) } - else -> { + else -> { Timber.w("Unsupported set_tweak value ${actionStrOrObj[Action.ACTION_OBJECT_SET_TWEAK_KEY]}") null } } } - else -> { + else -> { Timber.w("Unsupported action type $actionStrOrObj") null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ConditionResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ConditionResolver.kt index f8a930f987d1cd51ba5716f9ca5746e6ce159a63..d64ee5f77763477f70c47161741e567b2593b44e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ConditionResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ConditionResolver.kt @@ -22,15 +22,23 @@ import org.matrix.android.sdk.api.session.events.model.Event * This class as all required context needed to evaluate rules */ interface ConditionResolver { - fun resolveEventMatchCondition(event: Event, - condition: EventMatchCondition): Boolean + fun resolveEventMatchCondition( + event: Event, + condition: EventMatchCondition + ): Boolean - fun resolveRoomMemberCountCondition(event: Event, - condition: RoomMemberCountCondition): Boolean + fun resolveRoomMemberCountCondition( + event: Event, + condition: RoomMemberCountCondition + ): Boolean - fun resolveSenderNotificationPermissionCondition(event: Event, - condition: SenderNotificationPermissionCondition): Boolean + fun resolveSenderNotificationPermissionCondition( + event: Event, + condition: SenderNotificationPermissionCondition + ): Boolean - fun resolveContainsDisplayNameCondition(event: Event, - condition: ContainsDisplayNameCondition): Boolean + fun resolveContainsDisplayNameCondition( + event: Event, + condition: ContainsDisplayNameCondition + ): Boolean } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt index 69dd14ddc2c2468e6ea05150cf89c4dcf6a9a353..0bf14345b93c1b8b232ebd2222774ff62aaaa81e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/ContainsDisplayNameCondition.kt @@ -39,7 +39,7 @@ class ContainsDisplayNameCondition : Condition { // EventType.ENCRYPTED -> { // event.root.getClearContent()?.toModel<MessageContent>() // } - else -> null + else -> null } ?: return false return message.body.caseInsensitiveFind(displayName) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt index 463f3c2a73d0b4870b8a2e2ae718bcffe5ead215..bba6fe602694411fea2c6ebe252300232d60ae7c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Kind.kt @@ -27,11 +27,11 @@ enum class Kind(val value: String) { fun fromString(value: String): Kind { return when (value) { - "event_match" -> EventMatch - "contains_display_name" -> ContainsDisplayName - "room_member_count" -> RoomMemberCount + "event_match" -> EventMatch + "contains_display_name" -> ContainsDisplayName + "room_member_count" -> RoomMemberCount "sender_notification_permission" -> SenderNotificationPermission - else -> Unrecognised + else -> Unrecognised } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushRuleService.kt index bc4860be1153d3aebb783d9d66b2c6aa1650643f..8f9c25fd30909fecaa4037772d886760b8b4d75e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushRuleService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/PushRuleService.kt @@ -34,10 +34,11 @@ interface PushRuleService { /** * Enables/Disables a push rule and updates the actions if necessary. + * @param kind the rule kind + * @param ruleId the rule id * @param enable Enables/Disables the rule * @param actions Actions to update if not null */ - suspend fun updatePushRuleActions(kind: RuleKind, ruleId: String, enable: Boolean, actions: List<Action>?) suspend fun removePushRule(kind: RuleKind, ruleId: String) @@ -50,8 +51,10 @@ interface PushRuleService { // fun fulfilledBingRule(event: Event, rules: List<PushRule>): PushRule? - fun resolveSenderNotificationPermissionCondition(event: Event, - condition: SenderNotificationPermissionCondition): Boolean + fun resolveSenderNotificationPermissionCondition( + event: Event, + condition: SenderNotificationPermissionCondition + ): Boolean interface PushRuleListener { fun onEvents(pushEvents: PushEvents) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt index 6973ff1372a30c0ec25620725e3597707d94f56e..db097fd92c980a4e55e66a20bfeb990690187fb1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RoomMemberCountCondition.kt @@ -47,8 +47,8 @@ class RoomMemberCountCondition( val numMembers = room.membershipService().getNumberOfJoinedMembers() return when (prefix) { - "<" -> numMembers < count - ">" -> numMembers > count + "<" -> numMembers < count + ">" -> numMembers > count "<=" -> numMembers <= count ">=" -> numMembers >= count else -> numMembers == count diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt index 1fc8329535460aa9176e6e368b7f4718be8e52c6..ec0936e4c89feb9716f80a8a7b784749f4a9f20b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushCondition.kt @@ -61,7 +61,7 @@ data class PushCondition( fun asExecutableCondition(rule: PushRule): Condition? { return when (Kind.fromString(kind)) { - Kind.EventMatch -> { + Kind.EventMatch -> { if (key != null && pattern != null) { EventMatchCondition(key, pattern, rule.ruleId == RuleIds.RULE_ID_CONTAIN_USER_NAME) } else { @@ -69,10 +69,10 @@ data class PushCondition( null } } - Kind.ContainsDisplayName -> { + Kind.ContainsDisplayName -> { ContainsDisplayNameCondition() } - Kind.RoomMemberCount -> { + Kind.RoomMemberCount -> { if (iz.isNullOrEmpty()) { Timber.e("Malformed ROOM_MEMBER_COUNT condition") null @@ -88,7 +88,7 @@ data class PushCondition( SenderNotificationPermissionCondition(key) } } - Kind.Unrecognised -> { + Kind.Unrecognised -> { Timber.e("Unknown kind $kind") null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt index 5bf42b8252a63f4dd258dac3ace31250f79e073e..9498ed002c4db4f9e0bdea12652b5d67f10c0a00 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt @@ -67,7 +67,7 @@ data class RuleSet( /** * Find a rule from its rule Id. * - * @param rules the rules list. + * @param rules the rules list. * @param ruleId the rule Id. * @return the bing rule if it exists, else null. */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt index 3a18cf1497ac49f79b228475b0e8ac92c3929cdb..5d2769ac3cbd774c5c78051101ee9b48316673b0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt @@ -22,6 +22,7 @@ import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataServic import org.matrix.android.sdk.api.session.room.alias.AliasService import org.matrix.android.sdk.api.session.room.call.RoomCallService import org.matrix.android.sdk.api.session.room.crypto.RoomCryptoService +import org.matrix.android.sdk.api.session.room.location.LocationSharingService import org.matrix.android.sdk.api.session.room.members.MembershipService import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.relation.RelationService @@ -163,4 +164,9 @@ interface Room { * Get the RoomVersionService associated to this Room. */ fun roomVersionService(): RoomVersionService + + /** + * Get the LocationSharingService associated to this Room. + */ + fun locationSharingService(): LocationSharingService } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt index cb70603e66cf4c9810b30995b92c055b4bdfc581..77092c4811a302b688402d2ff7d23efb207b7a75 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomDirectoryService.kt @@ -28,8 +28,10 @@ interface RoomDirectoryService { /** * Get rooms from directory. */ - suspend fun getPublicRooms(server: String?, - publicRoomsParams: PublicRoomsParams): PublicRoomsResponse + suspend fun getPublicRooms( + server: String?, + publicRoomsParams: PublicRoomsParams + ): PublicRoomsResponse /** * Get the visibility of a room in the directory. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt index 6d5551ddf02d43bfe53e872d4eed8201432626b1..5dfb8961e3ce0fb5a6630c025cde96ca49a64500 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomService.kt @@ -60,9 +60,11 @@ interface RoomService { * @param reason optional reason for joining the room * @param viaServers the servers to attempt to join the room through. One of the servers must be participating in the room. */ - suspend fun joinRoom(roomIdOrAlias: String, - reason: String? = null, - viaServers: List<String> = emptyList()) + suspend fun joinRoom( + roomIdOrAlias: String, + reason: String? = null, + viaServers: List<String> = emptyList() + ) /** * @param roomId the roomId of the room to join @@ -97,19 +99,29 @@ interface RoomService { */ fun getRoomSummary(roomIdOrAlias: String): RoomSummary? + /** + * A live [RoomSummary] associated with the room with id [roomId]. + * You can observe this summary to get dynamic data from this room, even if the room is not joined yet + */ + fun getRoomSummaryLive(roomId: String): LiveData<Optional<RoomSummary>> + /** * Get a snapshot list of room summaries. * @return the immutable list of [RoomSummary] */ - fun getRoomSummaries(queryParams: RoomSummaryQueryParams, - sortOrder: RoomSortOrder = RoomSortOrder.NONE): List<RoomSummary> + fun getRoomSummaries( + queryParams: RoomSummaryQueryParams, + sortOrder: RoomSortOrder = RoomSortOrder.NONE + ): List<RoomSummary> /** * Get a live list of room summaries. This list is refreshed as soon as the data changes. * @return the [LiveData] of List[RoomSummary] */ - fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams, - sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): LiveData<List<RoomSummary>> + fun getRoomSummariesLive( + queryParams: RoomSummaryQueryParams, + sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY + ): LiveData<List<RoomSummary>> /** * Get a snapshot list of Breadcrumbs. @@ -139,8 +151,10 @@ interface RoomService { /** * Resolve a room alias to a room ID. */ - suspend fun getRoomIdByAlias(roomAlias: String, - searchOnServer: Boolean): Optional<RoomAliasDescription> + suspend fun getRoomIdByAlias( + roomAlias: String, + searchOnServer: Boolean + ): Optional<RoomAliasDescription> /** * Delete a room alias. @@ -205,16 +219,27 @@ interface RoomService { /** * TODO Doc. */ - fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, - pagedListConfig: PagedList.Config = defaultPagedListConfig, - sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): LiveData<PagedList<RoomSummary>> + fun getPagedRoomSummariesLive( + queryParams: RoomSummaryQueryParams, + pagedListConfig: PagedList.Config = defaultPagedListConfig, + sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY + ): LiveData<PagedList<RoomSummary>> /** - * TODO Doc. + * Get's a live paged list from a filter that can be dynamically updated. + * + * @param queryParams The filter to use + * @param pagedListConfig The paged list configuration (page size, initial load, prefetch distance...) + * @param sortOrder defines how to sort the results + * @param getFlattenParents When true, the list of known parents and grand parents summaries will be resolved. + * This can have significant impact on performance, better be used only on manageable list (filtered by displayName, ..). */ - fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, - pagedListConfig: PagedList.Config = defaultPagedListConfig, - sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): UpdatableLivePageResult + fun getFilteredPagedRoomSummariesLive( + queryParams: RoomSummaryQueryParams, + pagedListConfig: PagedList.Config = defaultPagedListConfig, + sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY, + getFlattenParents: Boolean = false, + ): UpdatableLivePageResult /** * Return a LiveData on the number of rooms. @@ -240,8 +265,10 @@ interface RoomService { /** * Returns all the children of this space, as LiveData. */ - fun getFlattenRoomSummaryChildrenOfLive(spaceId: String?, - memberships: List<Membership> = Membership.activeMemberships()): LiveData<List<RoomSummary>> + fun getFlattenRoomSummaryChildrenOfLive( + spaceId: String?, + memberships: List<Membership> = Membership.activeMemberships() + ): LiveData<List<RoomSummary>> /** * Refreshes the RoomSummary LatestPreviewContent for the given @param roomId. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt index e721abd6a05456e08b315f48924a95a639719d82..9368ad6bf4056e9e9cb50936b475c2087d4b1dc6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt @@ -16,9 +16,28 @@ package org.matrix.android.sdk.api.session.room +/** + * Enum to sort room list. + */ enum class RoomSortOrder { + /** + * Sort room list by room ascending name. + */ NAME, + + /** + * Sort room list by room descending last activity. + */ ACTIVITY, + + /** + * Sort room list by room priority and last activity: favorite room first, low priority room last, + * then descending last activity. + */ PRIORITY_AND_ACTIVITY, + + /** + * Do not sort room list. Useful if the order does not matter. Order can be indeterminate. + */ NONE } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt index 5c74dcced1be6fe65fdb8024615de874e54cb36a..3d943473e4ebb34aa161bf5847be9cda0088da1c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt @@ -16,60 +16,99 @@ package org.matrix.android.sdk.api.session.room -import org.matrix.android.sdk.api.query.ActiveSpaceFilter import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.RoomCategoryFilter import org.matrix.android.sdk.api.query.RoomTagQueryFilter +import org.matrix.android.sdk.api.query.SpaceFilter import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomType import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams +/** + * Create a [RoomSummaryQueryParams] object, calling [init] with a [RoomSummaryQueryParams.Builder]. + */ fun roomSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) = {}): RoomSummaryQueryParams { - return RoomSummaryQueryParams.Builder().apply(init).build() -} - -fun spaceSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) = {}): SpaceSummaryQueryParams { return RoomSummaryQueryParams.Builder() .apply(init) - .apply { - includeType = listOf(RoomType.SPACE) - excludeType = null - roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS - } .build() } /** - * This class can be used to filter room summaries to use with: - * [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService]. + * Create a [SpaceSummaryQueryParams] object (which is a [RoomSummaryQueryParams]), calling [init] with a [RoomSummaryQueryParams.Builder]. + * This is specific for spaces, other filters will be applied after invoking [init] + */ +fun spaceSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) = {}): SpaceSummaryQueryParams { + return roomSummaryQueryParams { + init() + includeType = listOf(RoomType.SPACE) + excludeType = null + roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS + } +} + +/** + * This class can be used to filter room summaries to use with [RoomService]. + * It provides a [Builder]. + * [roomSummaryQueryParams] and [spaceSummaryQueryParams] can also be used to build an instance of this class. */ data class RoomSummaryQueryParams( - val roomId: QueryStringValue, + /** + * Query for the displayName of the room. The display name can be the value of the state event, + * or a value returned by [org.matrix.android.sdk.api.RoomDisplayNameFallbackProvider]. + */ val displayName: QueryStringValue, + /** + * Query for the canonical alias of the room. + */ val canonicalAlias: QueryStringValue, + /** + * Used to filter room by membership. + */ val memberships: List<Membership>, + /** + * Used to filter room by room category. + */ val roomCategoryFilter: RoomCategoryFilter?, + /** + * Used to filter room by room tag. + */ val roomTagQueryFilter: RoomTagQueryFilter?, + /** + * Used to filter room by room type. + * @see [includeType] + */ val excludeType: List<String?>?, + /** + * Used to filter room by room type. + * @see [excludeType] + */ val includeType: List<String?>?, - val activeSpaceFilter: ActiveSpaceFilter?, + /** + * Used to filter room using the current space. + */ + val spaceFilter: SpaceFilter?, + /** + * Used to filter room using the current group. + */ val activeGroupId: String? = null ) { + /** + * Builder for [RoomSummaryQueryParams]. + * [roomSummaryQueryParams] and [spaceSummaryQueryParams] can also be used to build an instance of [RoomSummaryQueryParams]. + */ class Builder { - var roomId: QueryStringValue = QueryStringValue.IsNotEmpty - var displayName: QueryStringValue = QueryStringValue.IsNotEmpty + var displayName: QueryStringValue = QueryStringValue.NoCondition var canonicalAlias: QueryStringValue = QueryStringValue.NoCondition var memberships: List<Membership> = Membership.all() - var roomCategoryFilter: RoomCategoryFilter? = RoomCategoryFilter.ALL + var roomCategoryFilter: RoomCategoryFilter? = null var roomTagQueryFilter: RoomTagQueryFilter? = null var excludeType: List<String?>? = listOf(RoomType.SPACE) var includeType: List<String?>? = null - var activeSpaceFilter: ActiveSpaceFilter = ActiveSpaceFilter.None + var spaceFilter: SpaceFilter? = null var activeGroupId: String? = null fun build() = RoomSummaryQueryParams( - roomId = roomId, displayName = displayName, canonicalAlias = canonicalAlias, memberships = memberships, @@ -77,7 +116,7 @@ data class RoomSummaryQueryParams( roomTagQueryFilter = roomTagQueryFilter, excludeType = excludeType, includeType = includeType, - activeSpaceFilter = activeSpaceFilter, + spaceFilter = spaceFilter, activeGroupId = activeGroupId ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/crypto/RoomCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/crypto/RoomCryptoService.kt index 6967e0c455026268851987b57839bd86c9f2cea5..606464382005e13a4151e85b85ec7aace6d46142 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/crypto/RoomCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/crypto/RoomCryptoService.kt @@ -28,7 +28,8 @@ interface RoomCryptoService { /** * Enable encryption of the room. - * @param Use force to ensure that this algorithm will be used. Otherwise this call + * @param algorithm the algorithm to set, default to [MXCRYPTO_ALGORITHM_MEGOLM] + * @param force Use force to ensure that this algorithm will be used. Otherwise this call * will throw if encryption is already setup or if the algorithm is not supported. Only to * be used by admins to fix misconfigured encryption. */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/LocationSharingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/LocationSharingService.kt new file mode 100644 index 0000000000000000000000000000000000000000..dd48d51f45a6a63ce67f4ac143e5581b6e85633c --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/location/LocationSharingService.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.room.location + +import androidx.lifecycle.LiveData +import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary + +/** + * Manage all location sharing related features. + */ +interface LocationSharingService { + fun getRunningLiveLocationShareSummaries(): LiveData<List<LiveLocationShareAggregatedSummary>> +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt index 8ef94b28968ee2bdf165883166c21702d1b27653..03298281309dd285e476babbbf9a096dafc0c3c2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/PowerLevelsContent.kt @@ -95,8 +95,8 @@ data class PowerLevelsContent( // the first implementation was a string value is String -> value.toInt() is Double -> value.toInt() - is Int -> value - else -> Role.Moderator.value + is Int -> value + else -> Role.Moderator.value } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomGuestAccessContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomGuestAccessContent.kt index ba274325bc5b4ff67789a4245c7766886bb5e0cb..7dd853d75d785dda18530866b016252b7f127639 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomGuestAccessContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomGuestAccessContent.kt @@ -30,9 +30,9 @@ data class RoomGuestAccessContent( @Json(name = "guest_access") val guestAccessStr: String? = null ) { val guestAccess: GuestAccess? = when (guestAccessStr) { - "can_join" -> GuestAccess.CanJoin + "can_join" -> GuestAccess.CanJoin "forbidden" -> GuestAccess.Forbidden - else -> { + else -> { Timber.w("Invalid value for GuestAccess: `$guestAccessStr`") null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibilityContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibilityContent.kt index da5c90ff0534f955b4b30e1fa37c3dfee9b21d32..39b4722c0c5e8953b799d269b590f1778022388d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibilityContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomHistoryVisibilityContent.kt @@ -26,10 +26,10 @@ data class RoomHistoryVisibilityContent( ) { val historyVisibility: RoomHistoryVisibility? = when (historyVisibilityStr) { "world_readable" -> RoomHistoryVisibility.WORLD_READABLE - "shared" -> RoomHistoryVisibility.SHARED - "invited" -> RoomHistoryVisibility.INVITED - "joined" -> RoomHistoryVisibility.JOINED - else -> { + "shared" -> RoomHistoryVisibility.SHARED + "invited" -> RoomHistoryVisibility.INVITED + "joined" -> RoomHistoryVisibility.JOINED + else -> { Timber.w("Invalid value for RoomHistoryVisibility: `$historyVisibilityStr`") null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesContent.kt index 3b338a36cd0056ee4ad5628c9c8342cf8df59da9..dbe21b16332237ea8beb22aea30f057c2fbd6663 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomJoinRulesContent.kt @@ -36,12 +36,12 @@ data class RoomJoinRulesContent( @Json(name = "allow") val allowList: List<RoomJoinRulesAllowEntry>? = null ) { val joinRules: RoomJoinRules? = when (joinRulesStr) { - "public" -> RoomJoinRules.PUBLIC - "invite" -> RoomJoinRules.INVITE - "knock" -> RoomJoinRules.KNOCK - "private" -> RoomJoinRules.PRIVATE + "public" -> RoomJoinRules.PUBLIC + "invite" -> RoomJoinRules.INVITE + "knock" -> RoomJoinRules.KNOCK + "private" -> RoomJoinRules.PRIVATE "restricted" -> RoomJoinRules.RESTRICTED - else -> { + else -> { Timber.w("Invalid value for RoomJoinRules: `$joinRulesStr`") null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt index 71c1d8303e5fe567e125d7a17e1747e45ca99d23..1ab23b7a11953b64a104a283c505aa6a1695ed48 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt @@ -28,65 +28,200 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent * It can be retrieved by [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService] */ data class RoomSummary( + /** + * The roomId of the room. + */ val roomId: String, - // Computed display name + /** + * Computed display name. The value of the state event `m.room.name` if not empty, else can be the value returned + * by [org.matrix.android.sdk.api.RoomDisplayNameFallbackProvider]. + */ val displayName: String = "", + /** + * The value of the live state event `m.room.name`. + */ val name: String = "", + /** + * The value of the live state event `m.room.topic`. + */ val topic: String = "", + /** + * The value of the live state event `m.room.avatar`. + */ val avatarUrl: String = "", + /** + * The value of the live state event `m.room.canonical_alias`. + */ val canonicalAlias: String? = null, + /** + * The list of all the aliases of this room. Content of the live state event `m.room.aliases`. + */ val aliases: List<String> = emptyList(), + /** + * The value of the live state event `m.room.join_rules`. + */ val joinRules: RoomJoinRules? = null, + /** + * True is this room is referenced in the account data `m.direct`. + */ val isDirect: Boolean = false, + /** + * If [isDirect] is true, this is the id of the first other member of this room. + */ val directUserId: String? = null, + /** + * If [isDirect] is true, this it the presence of the first other member of this room. + */ val directUserPresence: UserPresence? = null, + /** + * Number of members who have joined this room. + */ val joinedMembersCount: Int? = 0, + /** + * Number of members who are invited to this room. + */ val invitedMembersCount: Int? = 0, + /** + * Latest [TimelineEvent] which can be displayed in this room. Can be used in the room list. + */ val latestPreviewableEvent: TimelineEvent? = null, + /** + * List of other member ids of this room. + */ val otherMemberIds: List<String> = emptyList(), + /** + * Number of unread message in this room. + */ val notificationCount: Int = 0, + /** + * Number of unread and highlighted message in this room. + */ val highlightCount: Int = 0, + /** + * True if this room has unread messages. + */ val hasUnreadMessages: Boolean = false, + /** + * List of tags in this room. + */ val tags: List<RoomTag> = emptyList(), + /** + * Current user membership in this room. + */ val membership: Membership = Membership.NONE, + /** + * Versioning state of this room. + */ val versioningState: VersioningState = VersioningState.NONE, + /** + * Value of `m.fully_read` for this room. + */ val readMarkerId: String? = null, + /** + * Message saved as draft for this room. + */ val userDrafts: List<UserDraft> = emptyList(), + /** + * True if this room is encrypted. + */ val isEncrypted: Boolean, + /** + * Timestamp of the `m.room.encryption` state event. + */ val encryptionEventTs: Long?, + /** + * List of users who are currently typing on this room. + */ val typingUsers: List<SenderInfo>, + /** + * UserId of the user who has invited the current user to this room. + */ val inviterId: String? = null, + /** + * Breadcrumb index, util to sort rooms by last seen. + */ val breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS, + /** + * The room encryption trust level. + * @see [RoomEncryptionTrustLevel] + */ val roomEncryptionTrustLevel: RoomEncryptionTrustLevel? = null, + /** + * True if a message has not been sent in this room. + */ val hasFailedSending: Boolean = false, + /** + * The type of the room. Null for regular room. + * @see [RoomType] + */ val roomType: String? = null, + /** + * List of parent spaces. + */ val spaceParents: List<SpaceParentInfo>? = null, + /** + * List of children space. + */ val spaceChildren: List<SpaceChildInfo>? = null, + /** + * List of all the space parents. Will be empty by default, you have to explicitly request it. + */ + val flattenParents: List<RoomSummary> = emptyList(), + /** + * List of all the space parent Ids. + */ val flattenParentIds: List<String> = emptyList(), - val roomEncryptionAlgorithm: RoomEncryptionAlgorithm? = null + /** + * Information about the encryption algorithm, if this room is encrypted. + */ + val roomEncryptionAlgorithm: RoomEncryptionAlgorithm? = null, ) { - + /** + * True if [versioningState] is not [VersioningState.NONE]. + */ val isVersioned: Boolean get() = versioningState != VersioningState.NONE + /** + * True if [notificationCount] is not `0`. + */ val hasNewMessages: Boolean get() = notificationCount != 0 + /** + * True if the room has the tag `m.lowpriority`. + */ val isLowPriority: Boolean get() = hasTag(RoomTag.ROOM_TAG_LOW_PRIORITY) + /** + * True if the room has the tag `m.favourite`. + */ val isFavorite: Boolean get() = hasTag(RoomTag.ROOM_TAG_FAVOURITE) + /** + * True if [joinRules] is [RoomJoinRules.PUBLIC]. + */ val isPublic: Boolean get() = joinRules == RoomJoinRules.PUBLIC + /** + * Test if the room has the provided [tag]. + */ fun hasTag(tag: String) = tags.any { it.name == tag } + /** + * True if a 1-1 call can be started, i.e. the room has exactly 2 joined members. + */ val canStartCall: Boolean get() = joinedMembersCount == 2 companion object { + /** + * Constant to indicated that the room is not on the breadcrumbs. + * Used by [breadcrumbsIndex]. + */ const val NOT_IN_BREADCRUMBS = -1 } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/VersioningState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/VersioningState.kt index b4e7b10d4451c1627011d3267117b0319487bfe5..2e1668ebbba7f8a7dad45d9c0073ec8d6e0a6823 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/VersioningState.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/VersioningState.kt @@ -16,8 +16,22 @@ package org.matrix.android.sdk.api.session.room.model +/** + * Enum for the versioning state of a room. + */ enum class VersioningState { + /** + * The room is not versioned. + */ NONE, + + /** + * The room has been upgraded, but the new room is not joined yet. + */ UPGRADED_ROOM_NOT_JOINED, - UPGRADED_ROOM_JOINED + + /** + * The room has been upgraded, and the new room has been joined. + */ + UPGRADED_ROOM_JOINED, } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationShareAggregatedSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationShareAggregatedSummary.kt index 0b28d62f56b8d0ae02856d248a5272c6db131732..5ad1a482174d5888caf56ca47c80800d83d2f9c5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationShareAggregatedSummary.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/livelocation/LiveLocationShareAggregatedSummary.kt @@ -22,6 +22,10 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocati * Aggregation info concerning a live location share. */ data class LiveLocationShareAggregatedSummary( + val userId: String?, + /** + * Indicate whether the live is currently running. + */ val isActive: Boolean?, val endOfLiveTimestampMillis: Long?, val lastLocationDataContent: MessageBeaconLocationDataContent?, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVerificationAcceptContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVerificationAcceptContent.kt index 27619cf0a91db1a78e0ede5bd333f24bf4c474f9..33f61648dcb97fd1de1573e8d857368116156d50 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVerificationAcceptContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageVerificationAcceptContent.kt @@ -40,12 +40,14 @@ internal data class MessageVerificationAcceptContent( companion object : VerificationInfoAcceptFactory { - override fun create(tid: String, - keyAgreementProtocol: String, - hash: String, - commitment: String, - messageAuthenticationCode: String, - shortAuthenticationStrings: List<String>): VerificationInfoAccept { + override fun create( + tid: String, + keyAgreementProtocol: String, + hash: String, + commitment: String, + messageAuthenticationCode: String, + shortAuthenticationStrings: List<String> + ): VerificationInfoAccept { return MessageVerificationAcceptContent( hash, keyAgreementProtocol, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt index 0d094b835b3066a61df8299a46b7f9eea5c9074c..d34ea3c7d3658780e9b176d622957c9e7f2c1950 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt @@ -58,40 +58,50 @@ interface RelationService { * @param targetEventId the id of the event being reacted * @param reaction the reaction (preferably emoji) */ - fun sendReaction(targetEventId: String, - reaction: String): Cancelable + fun sendReaction( + targetEventId: String, + reaction: String + ): Cancelable /** * Undo a reaction (emoji) to the targetedEvent. * @param targetEventId the id of the event being reacted * @param reaction the reaction (preferably emoji) */ - suspend fun undoReaction(targetEventId: String, - reaction: String): Cancelable + suspend fun undoReaction( + targetEventId: String, + reaction: String + ): Cancelable /** * Edit a poll. - * @param pollType indicates open or closed polls * @param targetEvent The poll event to edit + * @param pollType indicates open or closed polls * @param question The edited question * @param options The edited options */ - fun editPoll(targetEvent: TimelineEvent, - pollType: PollType, - question: String, - options: List<String>): Cancelable + fun editPoll( + targetEvent: TimelineEvent, + pollType: PollType, + question: String, + options: List<String> + ): Cancelable /** * Edit a text message body. Limited to "m.text" contentType. * @param targetEvent The event to edit + * @param msgType the message type * @param newBodyText The edited body + * @param newBodyAutoMarkdown true to parse markdown on the new body * @param compatibilityBodyText The text that will appear on clients that don't support yet edition */ - fun editTextMessage(targetEvent: TimelineEvent, - msgType: String, - newBodyText: CharSequence, - newBodyAutoMarkdown: Boolean, - compatibilityBodyText: String = "* $newBodyText"): Cancelable + fun editTextMessage( + targetEvent: TimelineEvent, + msgType: String, + newBodyText: CharSequence, + newBodyAutoMarkdown: Boolean, + compatibilityBodyText: String = "* $newBodyText" + ): Cancelable /** * Edit a reply. This is a special case because replies contains fallback text as a prefix. @@ -101,10 +111,12 @@ interface RelationService { * @param newBodyText The edited body (stripped from in reply to content) * @param compatibilityBodyText The text that will appear on clients that don't support yet edition */ - fun editReply(replyToEdit: TimelineEvent, - originalTimelineEvent: TimelineEvent, - newBodyText: String, - compatibilityBodyText: String = "* $newBodyText"): Cancelable + fun editReply( + replyToEdit: TimelineEvent, + originalTimelineEvent: TimelineEvent, + newBodyText: String, + compatibilityBodyText: String = "* $newBodyText" + ): Cancelable /** * Get the edit history of the given event. @@ -125,11 +137,12 @@ interface RelationService { * @param showInThread If true, relation will be added to the reply in order to be visible from within threads * @param rootThreadEventId If show in thread is true then we need the rootThreadEventId to generate the relation */ - fun replyToMessage(eventReplied: TimelineEvent, - replyText: CharSequence, - autoMarkdown: Boolean = false, - showInThread: Boolean = false, - rootThreadEventId: String? = null + fun replyToMessage( + eventReplied: TimelineEvent, + replyText: CharSequence, + autoMarkdown: Boolean = false, + showInThread: Boolean = false, + rootThreadEventId: String? = null ): Cancelable? /** @@ -153,14 +166,16 @@ interface RelationService { * @param rootThreadEventId the root thread eventId * @param replyInThreadText the reply text * @param msgType the message type: MessageType.MSGTYPE_TEXT (default) or MessageType.MSGTYPE_EMOTE - * @param formattedText The formatted body using MessageType#FORMAT_MATRIX_HTML * @param autoMarkdown If true, the SDK will generate a formatted HTML message from the body text if markdown syntax is present + * @param formattedText The formatted body using MessageType#FORMAT_MATRIX_HTML * @param eventReplied the event referenced by the reply within a thread */ - fun replyInThread(rootThreadEventId: String, - replyInThreadText: CharSequence, - msgType: String = MessageType.MSGTYPE_TEXT, - autoMarkdown: Boolean = false, - formattedText: String? = null, - eventReplied: TimelineEvent? = null): Cancelable? + fun replyInThread( + rootThreadEventId: String, + replyInThreadText: CharSequence, + msgType: String = MessageType.MSGTYPE_TEXT, + autoMarkdown: Boolean = false, + formattedText: String? = null, + eventReplied: TimelineEvent? = null + ): Cancelable? } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt index 165a912b7fac0ed9898d38a45abf872b92938500..36993074aafe6305beb500061a640edbf2634da9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/PowerLevelsHelper.kt @@ -58,7 +58,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) { /** * Tell if an user can send an event of a certain type. * - * @param userId the id of the user to check for. + * @param userId the id of the user to check for. * @param isState true if the event is a state event (ie. state key is not null) * @param eventType the event type to check for * @return true if the user can send this type of event diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt index 5fe9bf6993a6c0afde6470782e8c0a3aca69269c..c5cc573458118de0d3d03989084e06465f71443c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/powerlevels/Role.kt @@ -32,11 +32,11 @@ sealed class Role(open val value: Int) : Comparable<Role> { // Order matters, default value should be checked after defined roles fun fromValue(value: Int, default: Int): Role { return when (value) { - Admin.value -> Admin + Admin.value -> Admin Moderator.value -> Moderator Default.value, - default -> Default - else -> Custom(value) + default -> Default + else -> Custom(value) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/read/ReadService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/read/ReadService.kt index 036628c02f53151ce68f2f9fdad1529ecb509539..dac1a1a773e5c28e73c2083a2ad6799712569462 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/read/ReadService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/read/ReadService.kt @@ -71,7 +71,7 @@ interface ReadService { /** * Returns a live list of read receipts for a given event. - * @param eventId: the event + * @param eventId the event */ fun getEventReadReceiptsLive(eventId: String): LiveData<List<ReadReceipt>> } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt index 4bb8abef8aaaff9c1b2292b10857a8799de9e4a5..661c3be5bd01a703d70bcba346b44f853e50bc54 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt @@ -62,6 +62,7 @@ interface SendService { * @param quotedEvent The event to which we will quote it's content. * @param text the text message to send * @param autoMarkdown If true, the SDK will generate a formatted HTML message from the body text if markdown syntax is present + * @param rootThreadEventId when this param is not null, the message will be sent in this specific thread * @return a [Cancelable] */ fun sendQuotedTextMessage(quotedEvent: TimelineEvent, text: String, autoMarkdown: Boolean, rootThreadEventId: String? = null): Cancelable @@ -75,10 +76,12 @@ interface SendService { * @param rootThreadEventId when this param is not null, the Media will be sent in this specific thread * @return a [Cancelable] */ - fun sendMedia(attachment: ContentAttachmentData, - compressBeforeSending: Boolean, - roomIds: Set<String>, - rootThreadEventId: String? = null): Cancelable + fun sendMedia( + attachment: ContentAttachmentData, + compressBeforeSending: Boolean, + roomIds: Set<String>, + rootThreadEventId: String? = null + ): Cancelable /** * Method to send a list of media asynchronously. @@ -89,10 +92,12 @@ interface SendService { * @param rootThreadEventId when this param is not null, all the Media will be sent in this specific thread * @return a [Cancelable] */ - fun sendMedias(attachments: List<ContentAttachmentData>, - compressBeforeSending: Boolean, - roomIds: Set<String>, - rootThreadEventId: String? = null): Cancelable + fun sendMedias( + attachments: List<ContentAttachmentData>, + compressBeforeSending: Boolean, + roomIds: Set<String>, + rootThreadEventId: String? = null + ): Cancelable /** * Send a poll to the room. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendState.kt index 7c806bf35b5634b032f418f4ee3479f32d67b65e..d058ff2840c44da3e0dbf0df639e17a2b897daa2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendState.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendState.kt @@ -17,27 +17,44 @@ package org.matrix.android.sdk.api.session.room.send enum class SendState { + /** + * The state is unknown. + */ UNKNOWN, - // the event has not been sent + /** + * The event has not been sent. + */ UNSENT, - // the event is encrypting + /** + * The event is encrypting. + */ ENCRYPTING, - // the event is currently sending + /** + * The event is currently sending. + */ SENDING, - // the event has been sent + /** + * The event has been sent. + */ SENT, - // the event has been received from server + /** + * The event has been received from server. + */ SYNCED, - // The event failed to be sent + /** + * The event failed to be sent. + */ UNDELIVERED, - // the event failed to be sent because some unknown devices have been found while encrypting it + /** + * The event failed to be sent because some unknown devices have been found while encrypting it. + */ FAILED_UNKNOWN_DEVICES; internal companion object { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/UserDraft.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/UserDraft.kt index 4ede1a66fc53a755917f0a493c16037fad70f400..e16405b3c08e806fcae6b8f13a16a819709c481c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/UserDraft.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/UserDraft.kt @@ -33,7 +33,7 @@ sealed interface UserDraft { fun isValid(): Boolean { return when (this) { is Regular -> content.isNotBlank() - else -> true + else -> true } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/sender/SenderInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/sender/SenderInfo.kt index 4c308c355a02163f30f533fb221c027b85364a47..d629df8b166965cd7892606a4a846af2433b7ac2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/sender/SenderInfo.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/sender/SenderInfo.kt @@ -29,9 +29,9 @@ data class SenderInfo( ) { val disambiguatedDisplayName: String get() = when { - displayName == null -> userId + displayName == null -> userId displayName.replaceSpaceChars().isBlank() -> "$displayName ($userId)" - isUniqueDisplayName -> displayName - else -> "$displayName ($userId)" + isUniqueDisplayName -> displayName + else -> "$displayName ($userId)" } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt index f6b56128d39aa8782e254550b8ecfc0d52f4b3f9..c79171f1564cb0e6c7960f9fd4b6080e806f2240 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/state/StateService.kt @@ -90,23 +90,29 @@ interface StateService { /** * Get a state event of the room. + * @param eventType An eventType. + * @param stateKey the query which will be done on the stateKey */ fun getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event? /** * Get a live state event of the room. + * @param eventType An eventType. + * @param stateKey the query which will be done on the stateKey */ fun getStateEventLive(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): LiveData<Optional<Event>> /** * Get state events of the room. * @param eventTypes Set of eventType. If empty, all state events will be returned + * @param stateKey the query which will be done on the stateKey */ fun getStateEvents(eventTypes: Set<String>, stateKey: QueryStringValue = QueryStringValue.NoCondition): List<Event> /** * Get live state events of the room. * @param eventTypes Set of eventType to observe. If empty, all state events will be observed + * @param stateKey the query which will be done on the stateKey */ fun getStateEventsLive(eventTypes: Set<String>, stateKey: QueryStringValue = QueryStringValue.NoCondition): LiveData<List<Event>> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadEditions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadEditions.kt index c8353cf0de0c7255aae7472e55b0eda99653eb3c..dc9cc886e9c4ed358bfef3c44655de2968024e99 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadEditions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadEditions.kt @@ -16,5 +16,7 @@ package org.matrix.android.sdk.api.session.room.threads.model -data class ThreadEditions(var rootThreadEdition: String? = null, - var latestThreadEdition: String? = null) +data class ThreadEditions( + var rootThreadEdition: String? = null, + var latestThreadEdition: String? = null +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadSummary.kt index 1ef972e889be030601c086df4d0ecff7a5249839..0b1aea1966a8404e72e4edfa9ab48d3d45e7864a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadSummary.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/threads/model/ThreadSummary.kt @@ -22,12 +22,14 @@ import org.matrix.android.sdk.api.session.room.sender.SenderInfo /** * The main thread Summary model, mainly used to display the thread list. */ -data class ThreadSummary(val roomId: String, - val rootEvent: Event?, - val latestEvent: Event?, - val rootEventId: String, - val rootThreadSenderInfo: SenderInfo, - val latestThreadSenderInfo: SenderInfo, - val isUserParticipating: Boolean, - val numberOfThreads: Int, - val threadEditions: ThreadEditions = ThreadEditions()) +data class ThreadSummary( + val roomId: String, + val rootEvent: Event?, + val latestEvent: Event?, + val rootEventId: String, + val rootThreadSenderInfo: SenderInfo, + val latestThreadSenderInfo: SenderInfo, + val isUserParticipating: Boolean, + val numberOfThreads: Int, + val threadEditions: ThreadEditions = ThreadEditions() +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt index b87bc25435cc249858ca133f763d2cce042e5c0c..9d8c8a13bd7aafaa44df96aff0c645550ba3fd40 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt @@ -30,6 +30,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary import org.matrix.android.sdk.api.session.room.model.ReadReceipt import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent @@ -89,6 +90,7 @@ data class TimelineEvent( /** * Get the metadata associated with a key. + * @param T type to cast the metadata to * @param key the key to get the metadata * @return the metadata */ @@ -137,10 +139,11 @@ fun TimelineEvent.getEditedEventId(): String? { */ fun TimelineEvent.getLastMessageContent(): MessageContent? { return when (root.getClearType()) { - EventType.STICKER -> root.getClearContent().toModel<MessageStickerContent>() - in EventType.POLL_START -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessagePollContent>() + EventType.STICKER -> root.getClearContent().toModel<MessageStickerContent>() + in EventType.POLL_START -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessagePollContent>() in EventType.STATE_ROOM_BEACON_INFO -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessageBeaconInfoContent>() - else -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel() + in EventType.BEACON_LOCATION_DATA -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel<MessageBeaconLocationDataContent>() + else -> (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt index bc1c9e57694ad23d2e1f7fd2b085629178dce161..ffb8b1ca4dae0441bcd0a7fb73fd8fa9eec29983 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/search/SearchService.kt @@ -33,12 +33,14 @@ interface SearchService { * @param afterLimit how many events after the result are returned. * @param includeProfile requests that the server returns the historic profile information for the users that sent the events that were returned. */ - suspend fun search(searchTerm: String, - roomId: String, - nextBatch: String?, - orderByRecent: Boolean, - limit: Int, - beforeLimit: Int, - afterLimit: Int, - includeProfile: Boolean): SearchResult + suspend fun search( + searchTerm: String, + roomId: String, + nextBatch: String?, + orderByRecent: Boolean, + limit: Int, + beforeLimit: Int, + afterLimit: Int, + includeProfile: Boolean + ): SearchResult } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/ActiveSpaceFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/KeyRef.kt similarity index 64% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/ActiveSpaceFilter.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/KeyRef.kt index 48619b9394bb85ba20700c3a9f63147ee750c64f..5a1bf67fdde108639fa2854b112936dbba01e04d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/query/ActiveSpaceFilter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/KeyRef.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,10 +14,9 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.query +package org.matrix.android.sdk.api.session.securestorage -sealed class ActiveSpaceFilter { - object None : ActiveSpaceFilter() - data class ActiveSpace(val currentSpaceId: String?) : ActiveSpaceFilter() - data class ExcludeSpace(val spaceId: String) : ActiveSpaceFilter() -} +data class KeyRef( + val keyId: String?, + val keySpec: SsssKeySpec? +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SharedSecretStorageService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SharedSecretStorageService.kt index 528e07196693656b73440350bd77f8795c01b0b7..bdbbd3ea846cbf4b4f3235090d60b08fceaa06b4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SharedSecretStorageService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/securestorage/SharedSecretStorageService.kt @@ -44,10 +44,12 @@ interface SharedSecretStorageService { * * @return key creation info */ - suspend fun generateKey(keyId: String, - key: SsssKeySpec?, - keyName: String, - keySigner: KeySigner?): SsssKeyCreationInfo + suspend fun generateKey( + keyId: String, + key: SsssKeySpec?, + keyName: String, + keySigner: KeySigner? + ): SsssKeyCreationInfo /** * Generates a SSSS key using the given passphrase. @@ -61,11 +63,13 @@ interface SharedSecretStorageService { * * @return key creation info */ - suspend fun generateKeyWithPassphrase(keyId: String, - keyName: String, - passphrase: String, - keySigner: KeySigner, - progressListener: ProgressListener?): SsssKeyCreationInfo + suspend fun generateKeyWithPassphrase( + keyId: String, + keyName: String, + passphrase: String, + keySigner: KeySigner, + progressListener: ProgressListener? + ): SsssKeyCreationInfo fun getKey(keyId: String): KeyInfoResult @@ -92,7 +96,7 @@ interface SharedSecretStorageService { * Clients MUST ensure that the key is trusted before using it to encrypt secrets. * * @param name The name of the secret - * @param secret The secret contents. + * @param secretBase64 The secret contents. * @param keys The list of (ID,privateKey) of the keys to use to encrypt the secret. */ suspend fun storeSecret(name: String, secretBase64: String, keys: List<KeyRef>) @@ -132,9 +136,4 @@ interface SharedSecretStorageService { fun checkShouldBeAbleToAccessSecrets(secretNames: List<String>, keyId: String?): IntegrityResult suspend fun requestSecret(name: String, myOtherDeviceId: String) - - data class KeyRef( - val keyId: String?, - val keySpec: SsssKeySpec? - ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt index c9903886285c8349e396fa784bccd311cbe31a31..61c03e08fcd56f53b6eb2f5b72d159a17a74cb3c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/Space.kt @@ -31,11 +31,13 @@ interface Space { */ fun spaceSummary(): RoomSummary? - suspend fun addChildren(roomId: String, - viaServers: List<String>?, - order: String?, + suspend fun addChildren( + roomId: String, + viaServers: List<String>?, + order: String?, // autoJoin: Boolean = false, - suggested: Boolean? = false) + suggested: Boolean? = false + ) fun getChildInfo(roomId: String): SpaceChildContent? diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt index 8f16b3b9c3fb7c711403af61b1feb9c67bbc341e..c7a64050146be35ae42b3cb5c663c4a625948337 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/space/SpaceService.kt @@ -37,15 +37,17 @@ interface SpaceService { /** * Just a shortcut for space creation for ease of use. */ - suspend fun createSpace(name: String, - topic: String?, - avatarUri: Uri?, - isPublic: Boolean, - roomAliasLocalPart: String? = null): String + suspend fun createSpace( + name: String, + topic: String?, + avatarUri: Uri?, + isPublic: Boolean, + roomAliasLocalPart: String? = null + ): String /** - * Get a space from a roomId. - * @param spaceId the roomId to look for. + * Get a space from a spaceId. + * @param spaceId the spaceId to look for. * @return a space with spaceId or null if room type is not space */ fun getSpace(spaceId: String): Space? @@ -54,36 +56,47 @@ interface SpaceService { * Try to resolve (peek) rooms and subspace in this space. * Use this call get preview of children of this space, particularly useful to get a * preview of rooms that you did not join yet. + * @param spaceId the spaceId to look for. */ suspend fun peekSpace(spaceId: String): SpacePeekResult /** * Get's information of a space by querying the server. + * + * @param spaceId the spaceId to look for. * @param suggestedOnly If true, return only child events and rooms where the m.space.child event has suggested: true. * @param limit a client-defined limit to the maximum number of rooms to return per page. Must be a non-negative integer. - * @param from: Optional. Pagination token given to retrieve the next set of rooms. Note that if a pagination token is provided, + * @param from Optional. Pagination token given to retrieve the next set of rooms. Note that if a pagination token is provided, * then the parameters given for suggested_only and max_depth must be the same. + * @param knownStateList when paginating, pass back the m.space.child state events */ - suspend fun querySpaceChildren(spaceId: String, - suggestedOnly: Boolean? = null, - limit: Int? = null, - from: String? = null, - // when paginating, pass back the m.space.child state events - knownStateList: List<Event>? = null): SpaceHierarchyData + suspend fun querySpaceChildren( + spaceId: String, + suggestedOnly: Boolean? = null, + limit: Int? = null, + from: String? = null, + knownStateList: List<Event>? = null + ): SpaceHierarchyData /** * Get a live list of space summaries. This list is refreshed as soon as the data changes. * @return the [LiveData] of List[SpaceSummary] */ - fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams, - sortOrder: RoomSortOrder = RoomSortOrder.NONE): LiveData<List<RoomSummary>> - - fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams, - sortOrder: RoomSortOrder = RoomSortOrder.NONE): List<RoomSummary> - - suspend fun joinSpace(spaceIdOrAlias: String, - reason: String? = null, - viaServers: List<String> = emptyList()): JoinSpaceResult + fun getSpaceSummariesLive( + queryParams: SpaceSummaryQueryParams, + sortOrder: RoomSortOrder = RoomSortOrder.NONE + ): LiveData<List<RoomSummary>> + + fun getSpaceSummaries( + spaceSummaryQueryParams: SpaceSummaryQueryParams, + sortOrder: RoomSortOrder = RoomSortOrder.NONE + ): List<RoomSummary> + + suspend fun joinSpace( + spaceIdOrAlias: String, + reason: String? = null, + viaServers: List<String> = emptyList() + ): JoinSpaceResult suspend fun rejectInvite(spaceId: String, reason: String?) @@ -98,7 +111,10 @@ interface SpaceService { /** * Let this room declare that it has a parent. + * @param childRoomId the space to set as a child + * @param parentSpaceId the parentId which will be set * @param canonical true if it should be the main parent of this room + * @param viaServers list of candidate servers that can be used to set the parent * In practice, well behaved rooms should only have one canonical parent, but given this is not enforced: * if multiple are present the client should select the one with the lowest room ID, as determined via a lexicographic utf-8 ordering. */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/statistics/StatisticEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/statistics/StatisticEvent.kt index 76755517ce25546e14c201be3880e94eb9e96b46..d9c77723936186358d3d5288db4695d74f913ae6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/statistics/StatisticEvent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/statistics/StatisticEvent.kt @@ -23,15 +23,19 @@ sealed interface StatisticEvent { /** * Initial sync request, response downloading, and treatment (parsing and storage) of response. */ - data class InitialSyncRequest(val requestDurationMs: Int, - val downloadDurationMs: Int, - val treatmentDurationMs: Int, - val nbOfJoinedRooms: Int) : StatisticEvent + data class InitialSyncRequest( + val requestDurationMs: Int, + val downloadDurationMs: Int, + val treatmentDurationMs: Int, + val nbOfJoinedRooms: Int + ) : StatisticEvent /** * Incremental sync event. */ - data class SyncTreatment(val durationMs: Int, - val afterPause: Boolean, - val nbOfJoinedRooms: Int) : StatisticEvent + data class SyncTreatment( + val durationMs: Int, + val afterPause: Boolean, + val nbOfJoinedRooms: Int + ) : StatisticEvent } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitSyncStep.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStep.kt similarity index 91% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitSyncStep.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStep.kt index 901c1b2ffbc756fee00d912d7c2eb51e3523b840..407585b003c448b3eb1b246d11df009982b37efd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/initsync/InitSyncStep.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/InitialSyncStep.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.matrix.android.sdk.api.session.initsync +package org.matrix.android.sdk.api.session.sync -enum class InitSyncStep { +enum class InitialSyncStep { ServerComputing, Downloading, ImportingAccount, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncRequestState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncRequestState.kt new file mode 100644 index 0000000000000000000000000000000000000000..4e932d49de85f04a16399b7a8bcd21ff9a2ab167 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncRequestState.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.sync + +sealed interface SyncRequestState { + /** + * For initial sync. + */ + interface InitialSyncRequestState : SyncRequestState + + object Idle : InitialSyncRequestState + data class InitialSyncProgressing( + val initialSyncStep: InitialSyncStep, + val percentProgress: Int = 0 + ) : InitialSyncRequestState + + /** + * For incremental sync. + */ + interface IncrementalSyncRequestState : SyncRequestState + + object IncrementalSyncIdle : IncrementalSyncRequestState + data class IncrementalSyncParsing( + val rooms: Int, + val toDevice: Int + ) : IncrementalSyncRequestState + + object IncrementalSyncError : IncrementalSyncRequestState + object IncrementalSyncDone : IncrementalSyncRequestState +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt new file mode 100644 index 0000000000000000000000000000000000000000..5b2bf651af891090d6776600d19dc16ddd29282a --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/SyncService.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.sync + +import androidx.lifecycle.LiveData +import kotlinx.coroutines.flow.SharedFlow +import org.matrix.android.sdk.api.session.sync.model.SyncResponse + +interface SyncService { + /** + * This method start the sync thread. + */ + fun startSync(fromForeground: Boolean) + + /** + * This method stop the sync thread. + */ + fun stopSync() + + /** + * Requires a one time background sync. + */ + fun requireBackgroundSync() + + /** + * Launches infinite self rescheduling background syncs via the WorkManager. + * + * While dozing, syncs will only occur during maintenance windows. + * For reliability it's recommended to also start a long running foreground service + * along with disabling battery optimizations. + */ + fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long) + + fun stopAnyBackgroundSync() + + /** + * This method returns the current sync state. + * @return the current [SyncState]. + */ + fun getSyncState(): SyncState + + /** + * This method allows to listen the sync state. + * @return a [LiveData] of [SyncState]. + */ + fun getSyncStateLive(): LiveData<SyncState> + + /** + * Get the [SyncRequestState] as a LiveData. + */ + fun getSyncRequestStateLive(): LiveData<SyncRequestState> + + /** + * This method returns a flow of SyncResponse. New value will be pushed through the sync thread. + */ + fun syncFlow(): SharedFlow<SyncResponse> + + /** + * This methods return true if an initial sync has been processed. + */ + fun hasAlreadySynced(): Boolean +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncAndroidService.kt similarity index 97% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncService.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncAndroidService.kt index ac81be2174b2234a359830f154ab8a9deb3227d3..8dee633b9c18555ecc02f63340af9283e15ced5a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/job/SyncAndroidService.kt @@ -46,7 +46,7 @@ import java.util.concurrent.atomic.AtomicBoolean * in order to be able to perform a sync even if the app is not running. * The <receiver> and <service> must be declared in the Manifest or the app using the SDK */ -abstract class SyncService : Service() { +abstract class SyncAndroidService : Service() { private var sessionId: String? = null private var mIsSelfDestroyed: Boolean = false @@ -84,7 +84,7 @@ abstract class SyncService : Service() { stopMe() } } - else -> { + else -> { val isInit = initialize(intent) onStart(isInitialSync) if (isInit) { @@ -158,9 +158,9 @@ abstract class SyncService : Service() { // never do that in foreground, let the syncThread work syncTask.execute(params) // Start sync if we were doing an initial sync and the syncThread is not launched yet - if (isInitialSync && session.getSyncState() == SyncState.Idle) { + if (isInitialSync && session.syncService().getSyncState() == SyncState.Idle) { val isForeground = !backgroundDetectionObserver.isInBackground - session.startSync(isForeground) + session.syncService().startSync(isForeground) } stopMe() } catch (throwable: Throwable) { @@ -210,7 +210,7 @@ abstract class SyncService : Service() { session = sessionComponent.session() sessionId = safeSessionId syncTask = sessionComponent.syncTask() - isInitialSync = !session.hasAlreadySynced() + isInitialSync = !session.syncService().hasAlreadySynced() networkConnectivityChecker = sessionComponent.networkConnectivityChecker() taskExecutor = sessionComponent.taskExecutor() coroutineDispatchers = sessionComponent.coroutineDispatchers() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncUnreadNotifications.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncUnreadNotifications.kt index 6618bceacd9327ff357a194623bc7d1191b03778..09273f56e63089e59901f269862ca467df181a5e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncUnreadNotifications.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/sync/model/RoomSyncUnreadNotifications.kt @@ -38,4 +38,5 @@ data class RoomSyncUnreadNotifications( /** * The number of highlighted unread messages (subset of notifications). */ - @Json(name = "highlight_count") val highlightCount: Int? = null) + @Json(name = "highlight_count") val highlightCount: Int? = null +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsResponse.kt index 9a30b4d764d26812d2784ee1e686e6742f4a3a60..ae728326ccdd9cef016f94a56e061416b3e4f84e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsResponse.kt @@ -30,8 +30,10 @@ data class TermsResponse( val policies: JsonDict? = null ) { - fun getLocalizedTerms(userLanguage: String, - defaultLanguage: String = "en"): List<LocalizedFlowDataLoginTerms> { + fun getLocalizedTerms( + userLanguage: String, + defaultLanguage: String = "en" + ): List<LocalizedFlowDataLoginTerms> { return policies?.map { val tos = policies[it.key] as? Map<*, *> ?: return@map null ((tos[userLanguage] ?: tos[defaultLanguage]) as? Map<*, *>)?.let { termsMap -> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt index 6c357b2224d04a7a511c963773cacea9323d2931..1ddce763d11faeedbab0a2399f81a28811b713c8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt @@ -24,10 +24,12 @@ interface TermsService { suspend fun getTerms(serviceType: ServiceType, baseUrl: String): GetTermsResponse - suspend fun agreeToTerms(serviceType: ServiceType, - baseUrl: String, - agreedUrls: List<String>, - token: String?) + suspend fun agreeToTerms( + serviceType: ServiceType, + baseUrl: String, + agreedUrls: List<String>, + token: String? + ) /** * Get the homeserver terms, from the register API. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadNotificationState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadNotificationState.kt index c110802d23a77d4463efe2fd459da3e81c196e1a..6825f8c27962da065f9ab687acc65b0752d0cc10 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadNotificationState.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/threads/ThreadNotificationState.kt @@ -20,14 +20,19 @@ package org.matrix.android.sdk.api.session.threads * This class defines the state of a thread notification. */ enum class ThreadNotificationState { - - // There are no new message + /** + * There are no new message. + */ NO_NEW_MESSAGE, - // There is at least one new message + /** + * There is at least one new message. + */ NEW_MESSAGE, - // The is at least one new message that should be highlighted - // ex. "Hello @aris.kotsomitopoulos" + /** + * The is at least one new message that should be highlighted. + * ex. "Hello @aris.kotsomitopoulos" + */ NEW_HIGHLIGHTED_MESSAGE; } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetPostAPIMediator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetPostAPIMediator.kt index edb49f4797f2ac9f6a1cb6862de12052ad03be20..0c224ff17c668c185bb0a26b354485259ee33fb9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetPostAPIMediator.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetPostAPIMediator.kt @@ -49,7 +49,7 @@ interface WidgetPostAPIMediator { /** * Send a boolean response. * - * @param response the response + * @param response the response * @param eventData the modular data */ fun sendBoolResponse(response: Boolean, eventData: JsonDict) @@ -57,7 +57,7 @@ interface WidgetPostAPIMediator { /** * Send an integer response. * - * @param response the response + * @param response the response * @param eventData the modular data */ fun sendIntegerResponse(response: Int, eventData: JsonDict) @@ -65,8 +65,9 @@ interface WidgetPostAPIMediator { /** * Send an object response. * - * @param klass the class of the response - * @param response the response + * @param T the generic type + * @param type the type of the response + * @param response the response * @param eventData the modular data */ fun <T> sendObjectResponse(type: Type, response: T?, eventData: JsonDict) @@ -81,7 +82,7 @@ interface WidgetPostAPIMediator { /** * Send an error. * - * @param message the error message + * @param message the error message * @param eventData the modular data */ fun sendError(message: String, eventData: JsonDict) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt index b06f8f7bc6c682d5d1ec3a297d7ab2c4b0a2ffd5..8ad6500d25bb6c7b366309a3151aa1fed2855dc4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/widgets/WidgetService.kt @@ -111,8 +111,8 @@ interface WidgetService { /** * Deactivate a widget in a room. It makes sure you have the rights to handle this. * - * @param roomId: the room where you want to deactivate the widget. - * @param widgetId: the widget to deactivate. + * @param roomId the room where you want to deactivate the widget. + * @param widgetId the widget to deactivate. */ suspend fun destroyRoomWidget(roomId: String, widgetId: String) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt index 8a29d003805072d445cee22c9249efbf6b2d97eb..26dd31dc2d4f214a12bbd9ef40121abfff635dee 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MatrixItem.kt @@ -33,9 +33,11 @@ sealed class MatrixItem( open val displayName: String?, open val avatarUrl: String? ) { - data class UserItem(override val id: String, - override val displayName: String? = null, - override val avatarUrl: String? = null) : + data class UserItem( + override val id: String, + override val displayName: String? = null, + override val avatarUrl: String? = null + ) : MatrixItem(id, displayName?.removeSuffix(IRC_PATTERN), avatarUrl) { init { @@ -45,10 +47,12 @@ sealed class MatrixItem( override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar) } - data class EveryoneInRoomItem(override val id: String, - override val displayName: String = NOTIFY_EVERYONE, - override val avatarUrl: String? = null, - val roomDisplayName: String? = null) : + data class EveryoneInRoomItem( + override val id: String, + override val displayName: String = NOTIFY_EVERYONE, + override val avatarUrl: String? = null, + val roomDisplayName: String? = null + ) : MatrixItem(id, displayName, avatarUrl) { init { if (BuildConfig.DEBUG) checkId() @@ -57,9 +61,11 @@ sealed class MatrixItem( override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar) } - data class EventItem(override val id: String, - override val displayName: String? = null, - override val avatarUrl: String? = null) : + data class EventItem( + override val id: String, + override val displayName: String? = null, + override val avatarUrl: String? = null + ) : MatrixItem(id, displayName, avatarUrl) { init { if (BuildConfig.DEBUG) checkId() @@ -68,9 +74,11 @@ sealed class MatrixItem( override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar) } - data class RoomItem(override val id: String, - override val displayName: String? = null, - override val avatarUrl: String? = null) : + data class RoomItem( + override val id: String, + override val displayName: String? = null, + override val avatarUrl: String? = null + ) : MatrixItem(id, displayName, avatarUrl) { init { if (BuildConfig.DEBUG) checkId() @@ -79,9 +87,11 @@ sealed class MatrixItem( override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar) } - data class SpaceItem(override val id: String, - override val displayName: String? = null, - override val avatarUrl: String? = null) : + data class SpaceItem( + override val id: String, + override val displayName: String? = null, + override val avatarUrl: String? = null + ) : MatrixItem(id, displayName, avatarUrl) { init { if (BuildConfig.DEBUG) checkId() @@ -90,9 +100,11 @@ sealed class MatrixItem( override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar) } - data class RoomAliasItem(override val id: String, - override val displayName: String? = null, - override val avatarUrl: String? = null) : + data class RoomAliasItem( + override val id: String, + override val displayName: String? = null, + override val avatarUrl: String? = null + ) : MatrixItem(id, displayName, avatarUrl) { init { if (BuildConfig.DEBUG) checkId() @@ -101,9 +113,11 @@ sealed class MatrixItem( override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar) } - data class GroupItem(override val id: String, - override val displayName: String? = null, - override val avatarUrl: String? = null) : + data class GroupItem( + override val id: String, + override val displayName: String? = null, + override val avatarUrl: String? = null + ) : MatrixItem(id, displayName, avatarUrl) { init { if (BuildConfig.DEBUG) checkId() @@ -124,20 +138,20 @@ sealed class MatrixItem( * Return the prefix as defined in the matrix spec (and not extracted from the id). */ private fun getIdPrefix() = when (this) { - is UserItem -> '@' - is EventItem -> '$' + is UserItem -> '@' + is EventItem -> '$' is SpaceItem, is RoomItem, is EveryoneInRoomItem -> '!' - is RoomAliasItem -> '#' - is GroupItem -> '+' + is RoomAliasItem -> '#' + is GroupItem -> '+' } fun firstLetterOfDisplayName(): String { val displayName = when (this) { // use the room display name for the notify everyone item is EveryoneInRoomItem -> roomDisplayName - else -> displayName + else -> displayName } return (displayName?.takeIf { it.isNotBlank() } ?: id) .let { dn -> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt index 934d61de45f99dde9255e22cdeb9b470e159f4e6..bd2dac9e3ccaef4f3c31870a2f33942f4f9e01e3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/SessionManager.kt @@ -27,8 +27,10 @@ import org.matrix.android.sdk.internal.session.SessionComponent import javax.inject.Inject @MatrixScope -internal class SessionManager @Inject constructor(private val matrixComponent: MatrixComponent, - private val sessionParamsStore: SessionParamsStore) { +internal class SessionManager @Inject constructor( + private val matrixComponent: MatrixComponent, + private val sessionParamsStore: SessionParamsStore +) { // SessionId -> SessionComponent private val sessionComponents = HashMap<String, SessionComponent>() @@ -53,7 +55,7 @@ internal class SessionManager @Inject constructor(private val matrixComponent: M fun stopSession(sessionId: String) { val sessionComponent = sessionComponents[sessionId] ?: throw RuntimeException("You don't have a session for id $sessionId") - sessionComponent.session().stopSync() + sessionComponent.session().syncService().stopSync() } fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt index 46fa63334cb9ed571eb94f33541de0045148cddf..ea4502824e2409f43c7ba3dbf28d567070db51d9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthAPI.kt @@ -98,15 +98,19 @@ internal interface AuthAPI { * https://github.com/matrix-org/matrix-doc/pull/2290 */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "register/{threePid}/requestToken") - suspend fun add3Pid(@Path("threePid") threePid: String, - @Body params: AddThreePidRegistrationParams): AddThreePidRegistrationResponse + suspend fun add3Pid( + @Path("threePid") threePid: String, + @Body params: AddThreePidRegistrationParams + ): AddThreePidRegistrationResponse /** * Validate 3pid. */ @POST - suspend fun validate3Pid(@Url url: String, - @Body params: ValidationCodeBody): SuccessResult + suspend fun validate3Pid( + @Url url: String, + @Body params: ValidationCodeBody + ): SuccessResult /** * Get the supported login flow. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt index 298e116199642fcedd68436976681ccd49f3327c..ddb70be906b15b8e84d872eab2ab9edc9fb6ef23 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/AuthModule.kt @@ -46,9 +46,11 @@ internal abstract class AuthModule { @JvmStatic @Provides @AuthDatabase - fun providesRealmConfiguration(context: Context, - realmKeysUtils: RealmKeysUtils, - authRealmMigration: AuthRealmMigration): RealmConfiguration { + fun providesRealmConfiguration( + context: Context, + realmKeysUtils: RealmKeysUtils, + authRealmMigration: AuthRealmMigration + ): RealmConfiguration { val old = File(context.filesDir, "matrix-sdk-auth") if (old.exists()) { old.renameTo(File(context.filesDir, "matrix-sdk-auth.realm")) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt index f1cfe3fee5ec6095122af7466c6edccbd9088592..61a423669c46ea9e43fae37217edadc743246712 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt @@ -20,7 +20,7 @@ import android.net.Uri import dagger.Lazy import okhttp3.OkHttpClient import org.matrix.android.sdk.api.MatrixPatterns -import org.matrix.android.sdk.api.MatrixPatterns.getDomain +import org.matrix.android.sdk.api.MatrixPatterns.getServerName import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig @@ -130,16 +130,7 @@ internal class DefaultAuthenticationService @Inject constructor( ?.trim { it == '/' } } - /** - * This is the entry point of the authentication service. - * homeServerConnectionConfig contains a homeserver URL probably entered by the user, which can be a - * valid homeserver API url, the url of Element Web, or anything else. - */ override suspend fun getLoginFlow(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult { - pendingSessionData = null - - pendingSessionStore.delete() - val result = runCatching { getLoginFlowInternal(homeServerConnectionConfig) } @@ -290,7 +281,7 @@ internal class DefaultAuthenticationService @Inject constructor( getLoginFlowResult(newAuthAPI, versions, wellknownResult.homeServerUrl) } - else -> throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) + else -> throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) } } @@ -323,8 +314,7 @@ internal class DefaultAuthenticationService @Inject constructor( } } - override val isRegistrationStarted: Boolean - get() = currentRegistrationWizard?.isRegistrationStarted == true + override fun isRegistrationStarted() = currentRegistrationWizard?.isRegistrationStarted() == true override fun getLoginWizard(): LoginWizard { return currentLoginWizard @@ -368,20 +358,24 @@ internal class DefaultAuthenticationService @Inject constructor( pendingSessionStore.delete() } - override suspend fun createSessionFromSso(homeServerConnectionConfig: HomeServerConnectionConfig, - credentials: Credentials): Session { + override suspend fun createSessionFromSso( + homeServerConnectionConfig: HomeServerConnectionConfig, + credentials: Credentials + ): Session { return sessionCreator.createSession(credentials, homeServerConnectionConfig) } - override suspend fun getWellKnownData(matrixId: String, - homeServerConnectionConfig: HomeServerConnectionConfig?): WellknownResult { + override suspend fun getWellKnownData( + matrixId: String, + homeServerConnectionConfig: HomeServerConnectionConfig? + ): WellknownResult { if (!MatrixPatterns.isUserId(matrixId)) { throw MatrixIdFailure.InvalidMatrixId } return getWellknownTask.execute( GetWellknownTask.Params( - domain = matrixId.getDomain(), + domain = matrixId.getServerName().substringBeforeLast(":"), homeServerConnectionConfig = homeServerConnectionConfig.orWellKnownDefaults() ) ) @@ -392,11 +386,13 @@ internal class DefaultAuthenticationService @Inject constructor( .withHomeServerUri("https://dummy.org") .build() - override suspend fun directAuthentication(homeServerConnectionConfig: HomeServerConnectionConfig, - matrixId: String, - password: String, - initialDeviceName: String, - deviceId: String?): Session { + override suspend fun directAuthentication( + homeServerConnectionConfig: HomeServerConnectionConfig, + matrixId: String, + password: String, + initialDeviceName: String, + deviceId: String? + ): Session { return directLoginTask.execute( DirectLoginTask.Params( homeServerConnectionConfig = homeServerConnectionConfig, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt index 5be480f633b8096c8211f83051e7a34d9429d22e..5f0a2298cb670acad891450f0a6a68adbea4bca7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/data/PasswordLoginParams.kt @@ -31,7 +31,8 @@ internal data class PasswordLoginParams( @Json(name = "password") val password: String, @Json(name = "type") override val type: String, @Json(name = "initial_device_display_name") val deviceDisplayName: String?, - @Json(name = "device_id") val deviceId: String?) : LoginParams { + @Json(name = "device_id") val deviceId: String? +) : LoginParams { companion object { private const val IDENTIFIER_KEY_TYPE = "type" @@ -47,10 +48,12 @@ internal data class PasswordLoginParams( private const val IDENTIFIER_KEY_COUNTRY = "country" private const val IDENTIFIER_KEY_PHONE = "phone" - fun userIdentifier(user: String, - password: String, - deviceDisplayName: String?, - deviceId: String?): PasswordLoginParams { + fun userIdentifier( + user: String, + password: String, + deviceDisplayName: String?, + deviceId: String? + ): PasswordLoginParams { return PasswordLoginParams( identifier = mapOf( IDENTIFIER_KEY_TYPE to IDENTIFIER_KEY_TYPE_USER, @@ -63,11 +66,13 @@ internal data class PasswordLoginParams( ) } - fun thirdPartyIdentifier(medium: String, - address: String, - password: String, - deviceDisplayName: String?, - deviceId: String?): PasswordLoginParams { + fun thirdPartyIdentifier( + medium: String, + address: String, + password: String, + deviceDisplayName: String?, + deviceId: String? + ): PasswordLoginParams { return PasswordLoginParams( identifier = mapOf( IDENTIFIER_KEY_TYPE to IDENTIFIER_KEY_TYPE_THIRD_PARTY, @@ -81,11 +86,13 @@ internal data class PasswordLoginParams( ) } - fun phoneIdentifier(country: String, - phone: String, - password: String, - deviceDisplayName: String?, - deviceId: String?): PasswordLoginParams { + fun phoneIdentifier( + country: String, + phone: String, + password: String, + deviceDisplayName: String?, + deviceId: String? + ): PasswordLoginParams { return PasswordLoginParams( identifier = mapOf( IDENTIFIER_KEY_TYPE to IDENTIFIER_KEY_TYPE_PHONE, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmPendingSessionStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmPendingSessionStore.kt index 13f26e321dad8c0abd52d863eabd50caa7ce4c87..aae8ff8419dd9bd3292b17637f1070e186b50f80 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmPendingSessionStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmPendingSessionStore.kt @@ -23,9 +23,10 @@ import org.matrix.android.sdk.internal.database.awaitTransaction import org.matrix.android.sdk.internal.di.AuthDatabase import javax.inject.Inject -internal class RealmPendingSessionStore @Inject constructor(private val mapper: PendingSessionMapper, - @AuthDatabase - private val realmConfiguration: RealmConfiguration +internal class RealmPendingSessionStore @Inject constructor( + private val mapper: PendingSessionMapper, + @AuthDatabase + private val realmConfiguration: RealmConfiguration ) : PendingSessionStore { override suspend fun savePendingSessionData(pendingSessionData: PendingSessionData) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmSessionParamsStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmSessionParamsStore.kt index 235ef6b7092ef39e6f6080f1329372cf804a12e5..4c3e3ca824d56f8cfa135215d4922875e4d8f43b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmSessionParamsStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/db/RealmSessionParamsStore.kt @@ -28,9 +28,10 @@ import org.matrix.android.sdk.internal.di.AuthDatabase import timber.log.Timber import javax.inject.Inject -internal class RealmSessionParamsStore @Inject constructor(private val mapper: SessionParamsMapper, - @AuthDatabase - private val realmConfiguration: RealmConfiguration +internal class RealmSessionParamsStore @Inject constructor( + private val mapper: SessionParamsMapper, + @AuthDatabase + private val realmConfiguration: RealmConfiguration ) : SessionParamsStore { override fun getLast(): SessionParams? { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt index 058395113837ddc975a864c71d3aba04ae33b7d5..20b056f1c79bcd3300a09d281e89e8c7a122e5d2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DefaultLoginWizard.kt @@ -52,10 +52,12 @@ internal class DefaultLoginWizard( return getProfileTask.execute(GetProfileTask.Params(matrixId)) } - override suspend fun login(login: String, - password: String, - initialDeviceName: String, - deviceId: String?): Session { + override suspend fun login( + login: String, + password: String, + initialDeviceName: String, + deviceId: String? + ): Session { val loginParams = if (Patterns.EMAIL_ADDRESS.matcher(login).matches()) { PasswordLoginParams.thirdPartyIdentifier( medium = ThreePidMedium.EMAIL, @@ -101,7 +103,7 @@ internal class DefaultLoginWizard( return sessionCreator.createSession(credentials, pendingSessionData.homeServerConnectionConfig) } - override suspend fun resetPassword(email: String, newPassword: String) { + override suspend fun resetPassword(email: String) { val param = RegisterAddThreePidTask.Params( RegisterThreePid.Email(email), pendingSessionData.clientSecret, @@ -115,18 +117,16 @@ internal class DefaultLoginWizard( authAPI.resetPassword(AddThreePidRegistrationParams.from(param)) } - pendingSessionData = pendingSessionData.copy(resetPasswordData = ResetPasswordData(newPassword, result)) + pendingSessionData = pendingSessionData.copy(resetPasswordData = ResetPasswordData(result)) .also { pendingSessionStore.savePendingSessionData(it) } } - override suspend fun resetPasswordMailConfirmed() { - val safeResetPasswordData = pendingSessionData.resetPasswordData - ?: throw IllegalStateException("developer error, no reset password in progress") - + override suspend fun resetPasswordMailConfirmed(newPassword: String) { + val resetPasswordData = pendingSessionData.resetPasswordData ?: throw IllegalStateException("Developer error - Must call resetPassword first") val param = ResetPasswordMailConfirmed.create( pendingSessionData.clientSecret, - safeResetPasswordData.addThreePidRegistrationResponse.sid, - safeResetPasswordData.newPassword + resetPasswordData.addThreePidRegistrationResponse.sid, + newPassword ) executeRequest(null) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt index 28706c7e8081edab796743bbcd9fbf498680cd93..c9311867c8c6bffee491b9ae835fdc5a4b586cca 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/DirectLoginTask.kt @@ -73,7 +73,7 @@ internal class DefaultDirectLoginTask @Inject constructor( homeServerUrl, throwable.fingerprint ) - else -> throwable + else -> throwable } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordData.kt index a65ec38d6d851be2bfa9444bc38c351fba1059f3..87a7b346dcf26ed33fe6dbf72661c93ba84dc78d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordData.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/login/ResetPasswordData.kt @@ -24,6 +24,5 @@ import org.matrix.android.sdk.internal.auth.registration.AddThreePidRegistration */ @JsonClass(generateAdapter = true) internal data class ResetPasswordData( - val newPassword: String, val addThreePidRegistrationResponse: AddThreePidRegistrationResponse ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt index 2f05864d3bfb0252da8de2a399accd47edf75a9d..f0cb6ebd6ddf656686e9e959c9c9efaca78b6e0a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt @@ -84,7 +84,7 @@ internal data class AddThreePidRegistrationParams( companion object { fun from(params: RegisterAddThreePidTask.Params): AddThreePidRegistrationParams { return when (params.threePid) { - is RegisterThreePid.Email -> AddThreePidRegistrationParams( + is RegisterThreePid.Email -> AddThreePidRegistrationParams( email = params.threePid.email, clientSecret = params.clientSecret, sendAttempt = params.sendAttempt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt index 8f00f3440c02e2129ad1a0a378b6d5a0f3d7818c..d6ec0297b4a88e900805f0ec15e7c0c8466305a3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt @@ -49,29 +49,29 @@ internal class DefaultRegistrationWizard( private val validateCodeTask: ValidateCodeTask = DefaultValidateCodeTask(authAPI) private val registerCustomTask: RegisterCustomTask = DefaultRegisterCustomTask(authAPI) - override val currentThreePid: String? - get() { - return when (val threePid = pendingSessionData.currentThreePidData?.threePid) { - is RegisterThreePid.Email -> threePid.email - is RegisterThreePid.Msisdn -> { - // Take formatted msisdn if provided by the server - pendingSessionData.currentThreePidData?.addThreePidRegistrationResponse?.formattedMsisdn?.takeIf { it.isNotBlank() } ?: threePid.msisdn - } - null -> null + override fun getCurrentThreePid(): String? { + return when (val threePid = pendingSessionData.currentThreePidData?.threePid) { + is RegisterThreePid.Email -> threePid.email + is RegisterThreePid.Msisdn -> { + // Take formatted msisdn if provided by the server + pendingSessionData.currentThreePidData?.addThreePidRegistrationResponse?.formattedMsisdn?.takeIf { it.isNotBlank() } ?: threePid.msisdn } + null -> null } + } - override val isRegistrationStarted: Boolean - get() = pendingSessionData.isRegistrationStarted + override fun isRegistrationStarted() = pendingSessionData.isRegistrationStarted override suspend fun getRegistrationFlow(): RegistrationResult { val params = RegistrationParams() return performRegistrationRequest(params) } - override suspend fun createAccount(userName: String?, - password: String?, - initialDeviceDisplayName: String?): RegistrationResult { + override suspend fun createAccount( + userName: String?, + password: String?, + initialDeviceDisplayName: String? + ): RegistrationResult { val params = RegistrationParams( username = userName, password = password, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegisterAddThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegisterAddThreePidTask.kt index 54a8ba0e6ce94786fd7e61f9cae3ee9da1c1ed20..b84ed613615a0399200f1e53fd6584362dae7474 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegisterAddThreePidTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegisterAddThreePidTask.kt @@ -41,7 +41,7 @@ internal class DefaultRegisterAddThreePidTask( private fun RegisterThreePid.toPath(): String { return when (this) { - is RegisterThreePid.Email -> "email" + is RegisterThreePid.Email -> "email" is RegisterThreePid.Msisdn -> "msisdn" } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ThreePidData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ThreePidData.kt index c8f71af3065192a56a5812e80d15d2ed49213b35..dde0a44ea06d6a19adbb34800448ee477a30d191 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ThreePidData.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/ThreePidData.kt @@ -40,11 +40,13 @@ internal data class ThreePidData( } companion object { - fun from(threePid: RegisterThreePid, - addThreePidRegistrationResponse: AddThreePidRegistrationResponse, - registrationParams: RegistrationParams): ThreePidData { + fun from( + threePid: RegisterThreePid, + addThreePidRegistrationResponse: AddThreePidRegistrationResponse, + registrationParams: RegistrationParams + ): ThreePidData { return when (threePid) { - is RegisterThreePid.Email -> + is RegisterThreePid.Email -> ThreePidData(threePid.email, "", "", addThreePidRegistrationResponse, registrationParams) is RegisterThreePid.Msisdn -> ThreePidData("", threePid.msisdn, threePid.countryCode, addThreePidRegistrationResponse, registrationParams) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt index 9b135c347d427728cd46d0f2fee3983cd93df6d8..8118f9faff3161d6a4196c3adf05c3b35c0f2a0c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/UIAExt.kt @@ -35,9 +35,11 @@ import kotlin.coroutines.suspendCoroutine * @return UiaResult if UIA handled, failed or cancelled * */ -internal suspend fun handleUIA(failure: Throwable, - interceptor: UserInteractiveAuthInterceptor, - retryBlock: suspend (UIABaseAuth) -> Unit): UiaResult { +internal suspend fun handleUIA( + failure: Throwable, + interceptor: UserInteractiveAuthInterceptor, + retryBlock: suspend (UIABaseAuth) -> Unit +): UiaResult { Timber.d("## UIA: check error ${failure.message}") val flowResponse = failure.toRegistrationFlowResponse() ?: return UiaResult.FAILURE.also { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt index 815f8de2de28b80c6a1067f943b2e67b3e21395c..cd38b68a85ec10a9b4101fc9c44061c6d2b80674 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersion.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.internal.auth.version +import org.matrix.android.sdk.api.extensions.ensureNotEmpty + /** * Values will take the form "rX.Y.Z". * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-versions @@ -33,19 +35,19 @@ internal data class HomeServerVersion( minor < other.minor -> -1 patch > other.patch -> 1 patch < other.patch -> -1 - else -> 0 + else -> 0 } } companion object { - internal val pattern = Regex("""[r|v](\d+)\.(\d+)\.(\d+)""") + internal val pattern = Regex("""[r|v](\d+)\.(\d+)(?:\.(\d+))?""") internal fun parse(value: String): HomeServerVersion? { val result = pattern.matchEntire(value) ?: return null return HomeServerVersion( major = result.groupValues[1].toInt(), minor = result.groupValues[2].toInt(), - patch = result.groupValues[3].toInt() + patch = result.groupValues.getOrNull(index = 3)?.ensureNotEmpty()?.toInt() ?: 0 ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt index 2265526484bd5b734ea2cedeb5c111c953b3b3cc..c69a8590168db42769ceb713adb9087d09681e58 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt @@ -110,10 +110,12 @@ internal abstract class CryptoModule { @Provides @CryptoDatabase @SessionScope - fun providesRealmConfiguration(@SessionFilesDirectory directory: File, - @UserMd5 userMd5: String, - realmKeysUtils: RealmKeysUtils, - realmCryptoStoreMigration: RealmCryptoStoreMigration): RealmConfiguration { + fun providesRealmConfiguration( + @SessionFilesDirectory directory: File, + @UserMd5 userMd5: String, + realmKeysUtils: RealmKeysUtils, + realmCryptoStoreMigration: RealmCryptoStoreMigration + ): RealmConfiguration { return RealmConfiguration.Builder() .directory(directory) .apply { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt index b3e9eab9880b1f0fa8ec3d372940273abc42530b..eee1ee70aa91f1399388f69494c3e43df84adb38 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt @@ -46,6 +46,7 @@ internal class CryptoSessionInfoProvider @Inject constructor( } /** + * @param roomId the room Id * @param allActive if true return joined as well as invited, if false, only joined */ fun getRoomUserIds(roomId: String, allActive: Boolean): List<String> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index 11fa93dbe05753ac457afa7298de581415329123..719f366518fd685e41ebe0f75dda37bdd3321e9d 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -188,8 +188,8 @@ internal class DefaultCryptoService @Inject constructor( fun onStateEvent(roomId: String, event: Event) { when (event.type) { - EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) - EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) + EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) + EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) } } @@ -198,8 +198,8 @@ internal class DefaultCryptoService @Inject constructor( // handle state events if (event.isStateEvent()) { when (event.type) { - EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) - EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) + EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) + EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) } } @@ -508,7 +508,7 @@ internal class DefaultCryptoService @Inject constructor( /** * Provides the device information for a user id and a device Id. * - * @param userId the user id + * @param userId the user id * @param deviceId the device id */ override fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? { @@ -538,7 +538,7 @@ internal class DefaultCryptoService @Inject constructor( /** * Set the devices as known. * - * @param devices the devices. Note that the verified member of the devices in this list will not be updated by this method. + * @param devices the devices. Note that the verified member of the devices in this list will not be updated by this method. * @param callback the asynchronous callback */ override fun setDevicesKnown(devices: List<MXDeviceInfo>, callback: MatrixCallback<Unit>?) { @@ -576,8 +576,8 @@ internal class DefaultCryptoService @Inject constructor( * Update the blocked/verified state of the given device. * * @param trustLevel the new trust level - * @param userId the owner of the device - * @param deviceId the unique identifier for the device. + * @param userId the owner of the device + * @param deviceId the unique identifier for the device. */ override fun setDeviceVerification(trustLevel: DeviceTrustLevel, userId: String, deviceId: String) { setDeviceVerificationAction.handle(trustLevel, userId, deviceId) @@ -586,16 +586,18 @@ internal class DefaultCryptoService @Inject constructor( /** * Configure a room to use encryption. * - * @param roomId the room id to enable encryption in. - * @param algorithm the encryption config for the room. + * @param roomId the room id to enable encryption in. + * @param algorithm the encryption config for the room. * @param inhibitDeviceQuery true to suppress device list query for users in the room (for now) - * @param membersId list of members to start tracking their devices + * @param membersId list of members to start tracking their devices * @return true if the operation succeeds. */ - private suspend fun setEncryptionInRoom(roomId: String, - algorithm: String?, - inhibitDeviceQuery: Boolean, - membersId: List<String>): Boolean { + private suspend fun setEncryptionInRoom( + roomId: String, + algorithm: String?, + inhibitDeviceQuery: Boolean, + membersId: List<String> + ): Boolean { // If we already have encryption in this room, we should ignore this event // (for now at least. Maybe we should alert the user somehow?) val existingAlgorithm = cryptoStore.getRoomAlgorithm(roomId) @@ -618,8 +620,8 @@ internal class DefaultCryptoService @Inject constructor( val alg: IMXEncrypting? = when (algorithm) { MXCRYPTO_ALGORITHM_MEGOLM -> megolmEncryptionFactory.create(roomId) - MXCRYPTO_ALGORITHM_OLM -> olmEncryptionFactory.create(roomId) - else -> null + MXCRYPTO_ALGORITHM_OLM -> olmEncryptionFactory.create(roomId) + else -> null } if (alg != null) { @@ -687,14 +689,16 @@ internal class DefaultCryptoService @Inject constructor( * Encrypt an event content according to the configuration of the room. * * @param eventContent the content of the event. - * @param eventType the type of the event. - * @param roomId the room identifier the event will be sent. - * @param callback the asynchronous callback + * @param eventType the type of the event. + * @param roomId the room identifier the event will be sent. + * @param callback the asynchronous callback */ - override fun encryptEventContent(eventContent: Content, - eventType: String, - roomId: String, - callback: MatrixCallback<MXEncryptEventContentResult>) { + override fun encryptEventContent( + eventContent: Content, + eventType: String, + roomId: String, + callback: MatrixCallback<MXEncryptEventContentResult> + ) { // moved to crypto scope to have uptodate values cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { val userIds = getRoomUserIds(roomId) @@ -742,7 +746,7 @@ internal class DefaultCryptoService @Inject constructor( /** * Decrypt an event. * - * @param event the raw event. + * @param event the raw event. * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. * @return the MXEventDecryptionResult data, or throw in case of error */ @@ -754,7 +758,7 @@ internal class DefaultCryptoService @Inject constructor( /** * Decrypt an event asynchronously. * - * @param event the raw event. + * @param event the raw event. * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. * @param callback the callback to return data or null */ @@ -765,7 +769,7 @@ internal class DefaultCryptoService @Inject constructor( /** * Decrypt an event. * - * @param event the raw event. + * @param event the raw event. * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. * @return the MXEventDecryptionResult data, or null in case of error */ @@ -796,10 +800,10 @@ internal class DefaultCryptoService @Inject constructor( // Keys are imported directly, not waiting for end of sync onRoomKeyEvent(event) } - EventType.REQUEST_SECRET -> { + EventType.REQUEST_SECRET -> { secretShareManager.handleSecretRequest(event) } - EventType.ROOM_KEY_REQUEST -> { + EventType.ROOM_KEY_REQUEST -> { event.getClearContent().toModel<RoomKeyShareRequest>()?.let { req -> // We'll always get these because we send room key requests to // '*' (ie. 'all devices') which includes the sending device, @@ -811,13 +815,13 @@ internal class DefaultCryptoService @Inject constructor( } } } - EventType.SEND_SECRET -> { + EventType.SEND_SECRET -> { onSecretSendReceived(event) } - EventType.ROOM_KEY_WITHHELD -> { + EventType.ROOM_KEY_WITHHELD -> { onKeyWithHeldReceived(event) } - else -> { + else -> { // ignore } } @@ -879,10 +883,12 @@ internal class DefaultCryptoService @Inject constructor( /** * Returns true if handled by SDK, otherwise should be sent to application layer. */ - private fun handleSDKLevelGossip(secretName: String?, - secretValue: String): Boolean { + private fun handleSDKLevelGossip( + secretName: String?, + secretValue: String + ): Boolean { return when (secretName) { - MASTER_KEY_SSSS_NAME -> { + MASTER_KEY_SSSS_NAME -> { crossSigningService.onSecretMSKGossip(secretValue) true } @@ -898,13 +904,14 @@ internal class DefaultCryptoService @Inject constructor( keysBackupService.onSecretKeyGossip(secretValue) true } - else -> false + else -> false } } /** * Handle an m.room.encryption event. * + * @param roomId the room Id * @param event the encryption event. */ private fun onRoomEncryptionEvent(roomId: String, event: Event) { @@ -928,6 +935,7 @@ internal class DefaultCryptoService @Inject constructor( /** * Handle a change in the membership state of a member of a room. * + * @param roomId the room Id * @param event the membership event causing the change */ private fun onRoomMembershipEvent(roomId: String, event: Event) { @@ -996,7 +1004,7 @@ internal class DefaultCryptoService @Inject constructor( /** * Export the crypto keys. * - * @param password the password + * @param password the password * @param anIterationCount the encryption iteration count (0 means no encryption) */ private suspend fun exportRoomKeys(password: String, anIterationCount: Int): ByteArray { @@ -1015,14 +1023,16 @@ internal class DefaultCryptoService @Inject constructor( /** * Import the room keys. * - * @param roomKeysAsArray the room keys as array. - * @param password the password + * @param roomKeysAsArray the room keys as array. + * @param password the password * @param progressListener the progress listener * @return the result ImportRoomKeysResult */ - override suspend fun importRoomKeys(roomKeysAsArray: ByteArray, - password: String, - progressListener: ProgressListener?): ImportRoomKeysResult { + override suspend fun importRoomKeys( + roomKeysAsArray: ByteArray, + password: String, + progressListener: ProgressListener? + ): ImportRoomKeysResult { return withContext(coroutineDispatchers.crypto) { Timber.tag(loggerTag.value).v("importRoomKeys starts") @@ -1066,7 +1076,7 @@ internal class DefaultCryptoService @Inject constructor( * A success means there is no unknown devices. * If there are some unknown devices, a MXCryptoError.UnknownDevice exception is triggered. * - * @param userIds the user ids list + * @param userIds the user ids list * @param callback the asynchronous callback. */ fun checkUnknownDevices(userIds: List<String>, callback: MatrixCallback<Unit>) { @@ -1089,7 +1099,7 @@ internal class DefaultCryptoService @Inject constructor( * If false, it can still be overridden per-room. * If true, it overrides the per-room settings. * - * @param block true to unilaterally blacklist all + * @param block true to unilaterally blacklist all */ override fun setGlobalBlacklistUnverifiedDevices(block: Boolean) { cryptoStore.setGlobalBlacklistUnverifiedDevices(block) @@ -1129,8 +1139,8 @@ internal class DefaultCryptoService @Inject constructor( /** * Manages the room black-listing for unverified devices. * - * @param roomId the room id - * @param add true to add the room id to the list, false to remove it. + * @param roomId the room id + * @param add true to add the room id to the list, false to remove it. */ private fun setRoomBlacklistUnverifiedDevices(roomId: String, add: Boolean) { val roomIds = cryptoStore.getRoomsListBlacklistUnverifiedDevices().toMutableList() @@ -1149,7 +1159,7 @@ internal class DefaultCryptoService @Inject constructor( /** * Add this room to the ones which don't encrypt messages to unverified devices. * - * @param roomId the room id + * @param roomId the room id */ override fun setRoomBlacklistUnverifiedDevices(roomId: String) { setRoomBlacklistUnverifiedDevices(roomId, true) @@ -1158,7 +1168,7 @@ internal class DefaultCryptoService @Inject constructor( /** * Remove this room to the ones which don't encrypt messages to unverified devices. * - * @param roomId the room id + * @param roomId the room id */ override fun setRoomUnBlacklistUnverifiedDevices(roomId: String) { setRoomBlacklistUnverifiedDevices(roomId, false) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt index cd4e2a6d527663b4dd2a572ab20ce1cea4b969d1..4f3900adb95a9e95e1e78f7becb26b662f665e09 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt @@ -170,7 +170,7 @@ internal class DeviceListManager @Inject constructor( * Update the devices list statuses. * * @param changed the user ids list which have new devices - * @param left the user ids list which left a room + * @param left the user ids list which left a room */ fun handleDeviceListsChanges(changed: Collection<String>, left: Collection<String>) { Timber.v("## CRYPTO: handleDeviceListsChanges changed: ${changed.logLimit()} / left: ${left.logLimit()}") @@ -223,7 +223,7 @@ internal class DeviceListManager @Inject constructor( /** * The keys download succeeded. * - * @param userIds the userIds list + * @param userIds the userIds list * @param failures the failure map. */ private fun onKeysDownloadSucceed(userIds: List<String>, failures: Map<String, Map<String, Any>>?): MXUsersDevicesMap<CryptoDeviceInfo> { @@ -231,8 +231,8 @@ internal class DeviceListManager @Inject constructor( for ((k, value) in failures) { val statusCode = when (val status = value["status"]) { is Double -> status.toInt() - is Int -> status.toInt() - else -> 0 + is Int -> status.toInt() + else -> 0 } if (statusCode == 503) { synchronized(notReadyToRetryHS) { @@ -276,7 +276,7 @@ internal class DeviceListManager @Inject constructor( * Download the device keys for a list of users and stores the keys in the MXStore. * It must be called in getEncryptingThreadHandler() thread. * - * @param userIds The users to fetch. + * @param userIds The users to fetch. * @param forceDownload Always download the keys even if cached. */ suspend fun downloadKeys(userIds: List<String>?, forceDownload: Boolean): MXUsersDevicesMap<CryptoDeviceInfo> { @@ -421,9 +421,9 @@ internal class DeviceListManager @Inject constructor( * Validate device keys. * This method must called on getEncryptingThreadHandler() thread. * - * @param deviceKeys the device keys to validate. - * @param userId the id of the user of the device. - * @param deviceId the id of the device. + * @param deviceKeys the device keys to validate. + * @param userId the id of the user of the device. + * @param deviceId the id of the device. * @param previouslyStoredDeviceKeys the device keys we received before for this device * @return true if succeeds */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt index d6f881211c8c3f8848f6d1c840ff9503d90038da..c1d04eb22ba482fe4c7a8791233ef7730d478ad3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt @@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.content.OlmEventContent +import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter @@ -42,7 +43,7 @@ import javax.inject.Inject private const val SEND_TO_DEVICE_RETRY_COUNT = 3 -private val loggerTag = LoggerTag("CryptoSyncHandler", LoggerTag.CRYPTO) +private val loggerTag = LoggerTag("EventDecryptor", LoggerTag.CRYPTO) @SessionScope internal class EventDecryptor @Inject constructor( @@ -72,7 +73,7 @@ internal class EventDecryptor @Inject constructor( /** * Decrypt an event. * - * @param event the raw event. + * @param event the raw event. * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. * @return the MXEventDecryptionResult data, or throw in case of error */ @@ -84,7 +85,7 @@ internal class EventDecryptor @Inject constructor( /** * Decrypt an event asynchronously. * - * @param event the raw event. + * @param event the raw event. * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. * @param callback the callback to return data or null */ @@ -100,7 +101,7 @@ internal class EventDecryptor @Inject constructor( /** * Decrypt an event. * - * @param event the raw event. + * @param event the raw event. * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. * @return the MXEventDecryptionResult data, or null in case of error */ @@ -110,6 +111,16 @@ internal class EventDecryptor @Inject constructor( if (eventContent == null) { Timber.tag(loggerTag.value).e("decryptEvent : empty event content") throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON) + } else if (event.isRedacted()) { + // we shouldn't attempt to decrypt a redacted event because the content is cleared and decryption will fail because of null algorithm + return MXEventDecryptionResult( + clearEvent = mapOf( + "room_id" to event.roomId.orEmpty(), + "type" to EventType.MESSAGE, + "content" to emptyMap<String, Any>(), + "unsigned" to event.unsignedData.toContent() + ) + ) } else { val algorithm = eventContent["algorithm"]?.toString() val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, algorithm) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt index 28ddf291b216d987e785373a4a45eebad1ddf767..e4d322cadd3a148c840f33235b4ae905de57c0ae 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt @@ -44,7 +44,8 @@ private val loggerTag = LoggerTag("InboundGroupSessionStore", LoggerTag.CRYPTO) internal class InboundGroupSessionStore @Inject constructor( private val store: IMXCryptoStore, private val cryptoCoroutineScope: CoroutineScope, - private val coroutineDispatchers: MatrixCoroutineDispatchers) { + private val coroutineDispatchers: MatrixCoroutineDispatchers +) { private data class CacheKey( val sessionId: String, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt index 13f2fb861abca650f8d9616b2b3592429293bbfa..7f36224daec5f66fef7c29588b130428ac5b1f7d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt @@ -135,7 +135,7 @@ internal class IncomingKeyRequestManager @Inject constructor( // just add to the buffer incomingRequestBuffer.add(validMegolmRequest) } - MegolmRequestAction.Cancel -> { + MegolmRequestAction.Cancel -> { // ignore, we can't cancel as it's not known (probably already processed) // still notify app layer if it was passed up previously IncomingRoomKeyRequest.fromRestRequest(senderId, request, clock)?.let { iReq -> @@ -159,7 +159,7 @@ internal class IncomingKeyRequestManager @Inject constructor( MegolmRequestAction.Request -> { // it's already in buffer, nop keep existing } - MegolmRequestAction.Cancel -> { + MegolmRequestAction.Cancel -> { // discard the request in buffer incomingRequestBuffer.remove(existing) outgoingRequestScope.launch(coroutineDispatchers.computation) { @@ -369,9 +369,11 @@ internal class IncomingKeyRequestManager @Inject constructor( shareMegolmKey(validReq, requestingDevice, null) } - private suspend fun shareMegolmKey(validRequest: ValidMegolmRequestBody, - requestingDevice: CryptoDeviceInfo, - chainIndex: Long?): Boolean { + private suspend fun shareMegolmKey( + validRequest: ValidMegolmRequestBody, + requestingDevice: CryptoDeviceInfo, + chainIndex: Long? + ): Boolean { Timber.tag(loggerTag.value) .d("try to re-share Megolm Key at index $chainIndex for ${validRequest.shortDbgString()}") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXCryptoAlgorithms.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXCryptoAlgorithms.kt index 5a5ee9e6968cffaf6dae8bf8569a6b2cd59891f9..14b0e8e125588cd10cee0f3600125e92b190bfd8 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXCryptoAlgorithms.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXCryptoAlgorithms.kt @@ -32,7 +32,7 @@ internal object MXCryptoAlgorithms { return when (algorithm) { MXCRYPTO_ALGORITHM_MEGOLM, MXCRYPTO_ALGORITHM_OLM -> true - else -> false + else -> false } } @@ -47,7 +47,7 @@ internal object MXCryptoAlgorithms { return when (algorithm) { MXCRYPTO_ALGORITHM_MEGOLM, MXCRYPTO_ALGORITHM_OLM -> true - else -> false + else -> false } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXMegolmExportEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXMegolmExportEncryption.kt index e4a0f0376e04079a4cbc64c95972981b3f11c87a..e0d6c25d70173b12875bd107c42e772ef0ae2ef1 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXMegolmExportEncryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXMegolmExportEncryption.kt @@ -68,7 +68,7 @@ internal object MXMegolmExportEncryption { /** * Decrypt a megolm key file. * - * @param data the data to decrypt + * @param data the data to decrypt * @param password the password. * @return the decrypted output. * @throws Exception the failure reason @@ -138,9 +138,9 @@ internal object MXMegolmExportEncryption { /** * Encrypt a string into the megolm export format. * - * @param data the data to encrypt. - * @param password the password - * @param kdf_rounds the iteration count + * @param data the data to encrypt. + * @param password the password + * @param kdfRounds the iteration count * @return the encrypted data * @throws Exception the failure reason */ @@ -304,9 +304,9 @@ internal object MXMegolmExportEncryption { /** * Derive the AES and HMAC-SHA-256 keys for the file. * - * @param salt salt for pbkdf + * @param salt salt for pbkdf * @param iterations number of pbkdf iterations - * @param password password + * @param password password * @return the derived keys */ @Throws(Exception::class) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt index 5620cbf7693dab07ec101ae72b0869b2bf4ff306..24b6fd166f316866affb67f718b8e68bd1bf37c7 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt @@ -96,8 +96,9 @@ internal class MXOlmDevice @Inject constructor( // So, store these message indexes per timeline id. // // The first level keys are timeline ids. - // The second level keys are strings of form "<senderKey>|<session_id>|<message_index>" - private val inboundGroupSessionMessageIndexes: MutableMap<String, MutableSet<String>> = HashMap() + // The second level values is a Map that represents: + // "<senderKey>|<session_id>|<roomId>|<message_index>" --> eventId + private val inboundGroupSessionMessageIndexes: MutableMap<String, MutableMap<String, String>> = HashMap() init { // Retrieve the account from the store @@ -260,7 +261,7 @@ internal class MXOlmDevice @Inject constructor( * The new session will be stored in the MXStore. * * @param theirIdentityKey the remote user's Curve25519 identity key - * @param theirOneTimeKey the remote user's one-time Curve25519 key + * @param theirOneTimeKey the remote user's one-time Curve25519 key * @return the session id for the outbound session. */ fun createOutboundSession(theirIdentityKey: String, theirOneTimeKey: String): String? { @@ -299,8 +300,8 @@ internal class MXOlmDevice @Inject constructor( * Generate a new inbound session, given an incoming message. * * @param theirDeviceIdentityKey the remote user's Curve25519 identity key. - * @param messageType the message_type field from the received message (must be 0). - * @param ciphertext base64-encoded body from the received message. + * @param messageType the message_type field from the received message (must be 0). + * @param ciphertext base64-encoded body from the received message. * @return {{payload: string, session_id: string}} decrypted payload, and session id of new session. */ fun createInboundSession(theirDeviceIdentityKey: String, messageType: Int, ciphertext: String): Map<String, String>? { @@ -394,8 +395,8 @@ internal class MXOlmDevice @Inject constructor( * Encrypt an outgoing message using an existing session. * * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device. - * @param sessionId the id of the active session - * @param payloadString the payload to be encrypted and sent + * @param sessionId the id of the active session + * @param payloadString the payload to be encrypted and sent * @return the cipher text */ suspend fun encryptMessage(theirDeviceIdentityKey: String, sessionId: String, payloadString: String): Map<String, Any>? { @@ -427,10 +428,10 @@ internal class MXOlmDevice @Inject constructor( /** * Decrypt an incoming message using an existing session. * - * @param ciphertext the base64-encoded body from the received message. - * @param messageType message_type field from the received message. + * @param ciphertext the base64-encoded body from the received message. + * @param messageType message_type field from the received message. + * @param sessionId the id of the active session. * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device. - * @param sessionId the id of the active session. * @return the decrypted payload. */ @kotlin.jvm.Throws @@ -460,9 +461,9 @@ internal class MXOlmDevice @Inject constructor( * Determine if an incoming messages is a prekey message matching an existing session. * * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device. - * @param sessionId the id of the active session. - * @param messageType message_type field from the received message. - * @param ciphertext the base64-encoded body from the received message. + * @param sessionId the id of the active session. + * @param messageType message_type field from the received message. + * @param ciphertext the base64-encoded body from the received message. * @return YES if the received message is a prekey message which matchesthe given session. */ fun matchesSession(theirDeviceIdentityKey: String, sessionId: String, messageType: Int, ciphertext: String): Boolean { @@ -563,7 +564,7 @@ internal class MXOlmDevice @Inject constructor( /** * Encrypt an outgoing message with an outbound group session. * - * @param sessionId the id of the outbound group session. + * @param sessionId the id of the outbound group session. * @param payloadString the payload to be encrypted and sent. * @return ciphertext */ @@ -590,22 +591,24 @@ internal class MXOlmDevice @Inject constructor( /** * Add an inbound group session to the session store. * - * @param sessionId the session identifier. - * @param sessionKey base64-encoded secret key. - * @param roomId the id of the room in which this session will be used. - * @param senderKey the base64-encoded curve25519 key of the sender. + * @param sessionId the session identifier. + * @param sessionKey base64-encoded secret key. + * @param roomId the id of the room in which this session will be used. + * @param senderKey the base64-encoded curve25519 key of the sender. * @param forwardingCurve25519KeyChain Devices involved in forwarding this session to us. - * @param keysClaimed Other keys the sender claims. - * @param exportFormat true if the megolm keys are in export format + * @param keysClaimed Other keys the sender claims. + * @param exportFormat true if the megolm keys are in export format * @return true if the operation succeeds. */ - fun addInboundGroupSession(sessionId: String, - sessionKey: String, - roomId: String, - senderKey: String, - forwardingCurve25519KeyChain: List<String>, - keysClaimed: Map<String, String>, - exportFormat: Boolean): AddSessionResult { + fun addInboundGroupSession( + sessionId: String, + sessionKey: String, + roomId: String, + senderKey: String, + forwardingCurve25519KeyChain: List<String>, + keysClaimed: Map<String, String>, + exportFormat: Boolean + ): AddSessionResult { val candidateSession = OlmInboundGroupSessionWrapper2(sessionKey, exportFormat) val existingSessionHolder = tryOrNull { getInboundGroupSession(sessionId, senderKey, roomId) } val existingSession = existingSessionHolder?.wrapper @@ -752,70 +755,77 @@ internal class MXOlmDevice @Inject constructor( /** * Decrypt a received message with an inbound group session. * - * @param body the base64-encoded body of the encrypted message. - * @param roomId the room in which the message was received. - * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. + * @param body the base64-encoded body of the encrypted message. + * @param roomId the room in which the message was received. + * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. + * @param eventId the eventId of the message that will be decrypted * @param sessionId the session identifier. * @param senderKey the base64-encoded curve25519 key of the sender. - * @return the decrypting result. Nil if the sessionId is unknown. + * @return the decrypting result. Null if the sessionId is unknown. */ @Throws(MXCryptoError::class) - suspend fun decryptGroupMessage(body: String, - roomId: String, - timeline: String?, - sessionId: String, - senderKey: String): OlmDecryptionResult { + suspend fun decryptGroupMessage( + body: String, + roomId: String, + timeline: String?, + eventId: String, + sessionId: String, + senderKey: String + ): OlmDecryptionResult { val sessionHolder = getInboundGroupSession(sessionId, senderKey, roomId) val wrapper = sessionHolder.wrapper val inboundGroupSession = wrapper.olmInboundGroupSession ?: throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT, "Session is null") - // Check that the room id matches the original one for the session. This stops - // the HS pretending a message was targeting a different room. - if (roomId == wrapper.roomId) { - val decryptResult = try { - sessionHolder.mutex.withLock { - inboundGroupSession.decryptMessage(body) - } - } catch (e: OlmException) { - Timber.tag(loggerTag.value).e(e, "## decryptGroupMessage () : decryptMessage failed") - throw MXCryptoError.OlmError(e) - } - - if (timeline?.isNotBlank() == true) { - val timelineSet = inboundGroupSessionMessageIndexes.getOrPut(timeline) { mutableSetOf() } - - val messageIndexKey = senderKey + "|" + sessionId + "|" + decryptResult.mIndex - - if (timelineSet.contains(messageIndexKey)) { - val reason = String.format(MXCryptoError.DUPLICATE_MESSAGE_INDEX_REASON, decryptResult.mIndex) - Timber.tag(loggerTag.value).e("## decryptGroupMessage() timelineId=$timeline: $reason") - throw MXCryptoError.Base(MXCryptoError.ErrorType.DUPLICATED_MESSAGE_INDEX, reason) - } - - timelineSet.add(messageIndexKey) - } - - inboundGroupSessionStore.storeInBoundGroupSession(sessionHolder, sessionId, senderKey) - val payload = try { - val adapter = MoshiProvider.providesMoshi().adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE) - val payloadString = convertFromUTF8(decryptResult.mDecryptedMessage) - adapter.fromJson(payloadString) - } catch (e: Exception) { - Timber.tag(loggerTag.value).e("## decryptGroupMessage() : fails to parse the payload") - throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_DECRYPTED_FORMAT, MXCryptoError.BAD_DECRYPTED_FORMAT_TEXT_REASON) - } - - return OlmDecryptionResult( - payload, - wrapper.keysClaimed, - senderKey, - wrapper.forwardingCurve25519KeyChain - ) - } else { + if (roomId != wrapper.roomId) { + // Check that the room id matches the original one for the session. This stops + // the HS pretending a message was targeting a different room. val reason = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, wrapper.roomId) Timber.tag(loggerTag.value).e("## decryptGroupMessage() : $reason") throw MXCryptoError.Base(MXCryptoError.ErrorType.INBOUND_SESSION_MISMATCH_ROOM_ID, reason) } + val decryptResult = try { + sessionHolder.mutex.withLock { + inboundGroupSession.decryptMessage(body) + } + } catch (e: OlmException) { + Timber.tag(loggerTag.value).e(e, "## decryptGroupMessage () : decryptMessage failed") + throw MXCryptoError.OlmError(e) + } + + val messageIndexKey = senderKey + "|" + sessionId + "|" + roomId + "|" + decryptResult.mIndex + Timber.tag(loggerTag.value).v("##########################################################") + Timber.tag(loggerTag.value).v("## decryptGroupMessage() timeline: $timeline") + Timber.tag(loggerTag.value).v("## decryptGroupMessage() senderKey: $senderKey") + Timber.tag(loggerTag.value).v("## decryptGroupMessage() sessionId: $sessionId") + Timber.tag(loggerTag.value).v("## decryptGroupMessage() roomId: $roomId") + Timber.tag(loggerTag.value).v("## decryptGroupMessage() eventId: $eventId") + Timber.tag(loggerTag.value).v("## decryptGroupMessage() mIndex: ${decryptResult.mIndex}") + + if (timeline?.isNotBlank() == true) { + val replayAttackMap = inboundGroupSessionMessageIndexes.getOrPut(timeline) { mutableMapOf() } + if (replayAttackMap.contains(messageIndexKey) && replayAttackMap[messageIndexKey] != eventId) { + val reason = String.format(MXCryptoError.DUPLICATE_MESSAGE_INDEX_REASON, decryptResult.mIndex) + Timber.tag(loggerTag.value).e("## decryptGroupMessage() timelineId=$timeline: $reason") + throw MXCryptoError.Base(MXCryptoError.ErrorType.DUPLICATED_MESSAGE_INDEX, reason) + } + replayAttackMap[messageIndexKey] = eventId + } + inboundGroupSessionStore.storeInBoundGroupSession(sessionHolder, sessionId, senderKey) + val payload = try { + val adapter = MoshiProvider.providesMoshi().adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE) + val payloadString = convertFromUTF8(decryptResult.mDecryptedMessage) + adapter.fromJson(payloadString) + } catch (e: Exception) { + Timber.tag(loggerTag.value).e("## decryptGroupMessage() : fails to parse the payload") + throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_DECRYPTED_FORMAT, MXCryptoError.BAD_DECRYPTED_FORMAT_TEXT_REASON) + } + + return OlmDecryptionResult( + payload, + wrapper.keysClaimed, + senderKey, + wrapper.forwardingCurve25519KeyChain + ) } /** @@ -834,9 +844,9 @@ internal class MXOlmDevice @Inject constructor( /** * Verify an ed25519 signature on a JSON object. * - * @param key the ed25519 key. + * @param key the ed25519 key. * @param jsonDictionary the JSON object which was signed. - * @param signature the base64-encoded signature to be checked. + * @param signature the base64-encoded signature to be checked. * @throws Exception the exception */ @Throws(Exception::class) @@ -859,7 +869,7 @@ internal class MXOlmDevice @Inject constructor( * Search an OlmSession. * * @param theirDeviceIdentityKey the device key - * @param sessionId the session Id + * @param sessionId the session Id * @return the olm session */ private fun getSessionForDevice(theirDeviceIdentityKey: String, sessionId: String): OlmSessionWrapper? { @@ -873,9 +883,9 @@ internal class MXOlmDevice @Inject constructor( * Extract an InboundGroupSession from the session store and do some check. * inboundGroupSessionWithIdError describes the failure reason. * - * @param roomId the room where the session is used. * @param sessionId the session identifier. * @param senderKey the base64-encoded curve25519 key of the sender. + * @param roomId the room where the session is used. * @return the inbound group session. */ fun getInboundGroupSession(sessionId: String?, senderKey: String?, roomId: String?): InboundGroupSessionHolder { @@ -905,7 +915,7 @@ internal class MXOlmDevice @Inject constructor( /** * Determine if we have the keys for a given megolm session. * - * @param roomId room in which the message was received + * @param roomId room in which the message was received * @param senderKey base64-encoded curve25519 key of the sender * @param sessionId session identifier * @return true if the unbound session keys are known. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ObjectSigner.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ObjectSigner.kt index ab562d954a1f520f3b17f6b77b770da8b31337ec..3f4b633ea01aea5ceceb153f9df232aa298e22c2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ObjectSigner.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ObjectSigner.kt @@ -19,8 +19,10 @@ package org.matrix.android.sdk.internal.crypto import org.matrix.android.sdk.api.auth.data.Credentials import javax.inject.Inject -internal class ObjectSigner @Inject constructor(private val credentials: Credentials, - private val olmDevice: MXOlmDevice) { +internal class ObjectSigner @Inject constructor( + private val credentials: Credentials, + private val olmDevice: MXOlmDevice +) { /** * Sign Object. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmSessionStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmSessionStore.kt index fe280416ea25eea43d5bdf4815fdfd67d0389e77..4401a07192eaced5b97fc31bed7788ddd3d1a1a9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmSessionStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmSessionStore.kt @@ -39,7 +39,7 @@ internal class OlmSessionStore @Inject constructor(private val store: IMXCryptoS * Store a session between our own device and another device. * This will be called after the session has been created but also every time it has been used * in order to persist the correct state for next run - * @param olmSessionWrapper the end-to-end session. + * @param olmSessionWrapper the end-to-end session. * @param deviceKey the public key of the other device. */ @Synchronized diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt index d7652d07713b60ebf71fb6aae07cae5cf9ff2cf3..6b22cc09d6e8ff37f3ec348b81168a032faa9546 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt @@ -71,7 +71,8 @@ internal class OutgoingKeyRequestManager @Inject constructor( private val inboundGroupSessionStore: InboundGroupSessionStore, private val sendToDeviceTask: SendToDeviceTask, private val deviceListManager: DeviceListManager, - private val perSessionBackupQueryRateLimiter: PerSessionBackupQueryRateLimiter) { + private val perSessionBackupQueryRateLimiter: PerSessionBackupQueryRateLimiter +) { private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher() private val outgoingRequestScope = CoroutineScope(SupervisorJob() + dispatcher) @@ -180,13 +181,15 @@ internal class OutgoingKeyRequestManager @Inject constructor( } } - fun onRoomKeyForwarded(sessionId: String, - algorithm: String, - roomId: String, - senderKey: String, - fromDevice: String?, - fromIndex: Int, - event: Event) { + fun onRoomKeyForwarded( + sessionId: String, + algorithm: String, + roomId: String, + senderKey: String, + fromDevice: String?, + fromIndex: Int, + event: Event + ) { Timber.tag(loggerTag.value).d("Key forwarded for $sessionId from ${event.senderId}|$fromDevice at index $fromIndex") outgoingRequestScope.launch { sequencer.post { @@ -208,12 +211,14 @@ internal class OutgoingKeyRequestManager @Inject constructor( } } - fun onRoomKeyWithHeld(sessionId: String, - algorithm: String, - roomId: String, - senderKey: String, - fromDevice: String?, - event: Event) { + fun onRoomKeyWithHeld( + sessionId: String, + algorithm: String, + roomId: String, + senderKey: String, + fromDevice: String?, + event: Event + ) { outgoingRequestScope.launch { sequencer.post { Timber.tag(loggerTag.value).d("Withheld received for $sessionId from ${event.senderId}|$fromDevice") @@ -294,19 +299,19 @@ internal class OutgoingKeyRequestManager @Inject constructor( } knownRequest.forEach { request -> when (request.state) { - OutgoingRoomKeyRequestState.UNSENT -> { + OutgoingRoomKeyRequestState.UNSENT -> { if (request.fromIndex >= localKnownChainIndex) { // we have a good index we can cancel cryptoStore.deleteOutgoingRoomKeyRequest(request.requestId) } } - OutgoingRoomKeyRequestState.SENT -> { + OutgoingRoomKeyRequestState.SENT -> { // It was already sent, and index satisfied we can cancel if (request.fromIndex >= localKnownChainIndex) { cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING) } } - OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> { + OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> { // It is already marked to be cancelled } OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> { @@ -315,7 +320,7 @@ internal class OutgoingKeyRequestManager @Inject constructor( cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING) } } - OutgoingRoomKeyRequestState.SENT_THEN_CANCELED -> { + OutgoingRoomKeyRequestState.SENT_THEN_CANCELED -> { // was already canceled // if we need a better index, should we resend? } @@ -346,14 +351,14 @@ internal class OutgoingKeyRequestManager @Inject constructor( val existing = cryptoStore.getOutgoingRoomKeyRequest(requestBody) Timber.tag(loggerTag.value).v("Queueing key request exiting is ${existing?.state}") when (existing?.state) { - null -> { + null -> { // create a new one cryptoStore.getOrAddOutgoingRoomKeyRequest(requestBody, recipients, fromIndex) } - OutgoingRoomKeyRequestState.UNSENT -> { + OutgoingRoomKeyRequestState.UNSENT -> { // nothing it's new or not yet handled } - OutgoingRoomKeyRequestState.SENT -> { + OutgoingRoomKeyRequestState.SENT -> { // it was already requested Timber.tag(loggerTag.value).d("The session ${requestBody.sessionId} is already requested") if (force) { @@ -366,7 +371,7 @@ internal class OutgoingKeyRequestManager @Inject constructor( } } } - OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> { + OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> { // request is canceled only if I got the keys so what to do here... if (force) { cryptoStore.updateOutgoingRoomKeyRequestState(existing.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND) @@ -375,7 +380,7 @@ internal class OutgoingKeyRequestManager @Inject constructor( OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> { // It's already going to resend } - OutgoingRoomKeyRequestState.SENT_THEN_CANCELED -> { + OutgoingRoomKeyRequestState.SENT_THEN_CANCELED -> { if (force) { cryptoStore.deleteOutgoingRoomKeyRequest(existing.requestId) cryptoStore.getOrAddOutgoingRoomKeyRequest(requestBody, recipients, fromIndex) @@ -396,11 +401,11 @@ internal class OutgoingKeyRequestManager @Inject constructor( measureTimeMillis { toProcess.forEach { when (it.state) { - OutgoingRoomKeyRequestState.UNSENT -> handleUnsentRequest(it) - OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> handleRequestToCancel(it) + OutgoingRoomKeyRequestState.UNSENT -> handleUnsentRequest(it) + OutgoingRoomKeyRequestState.CANCELLATION_PENDING -> handleRequestToCancel(it) OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> handleRequestToCancelWillResend(it) OutgoingRoomKeyRequestState.SENT_THEN_CANCELED, - OutgoingRoomKeyRequestState.SENT -> { + OutgoingRoomKeyRequestState.SENT -> { // these are filtered out } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt index c2f494b4b3035b3e118ba8ca3b35edf91faf2d7b..d37e60d28942fbd2d487b50eb33dd3c3e7b704f4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt @@ -49,7 +49,7 @@ internal class RoomDecryptorProvider @Inject constructor( * If we already have a decryptor for the given room and algorithm, return * it. Otherwise try to instantiate it. * - * @param roomId the room id + * @param roomId the room id * @param algorithm the crypto algorithm * @return the decryptor * // TODO Create another method for the case of roomId is null @@ -85,7 +85,7 @@ internal class RoomDecryptorProvider @Inject constructor( } } } - else -> olmDecryptionFactory.create() + else -> olmDecryptionFactory.create() } if (!roomId.isNullOrEmpty()) { synchronized(roomDecryptors) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt index 1a8c160d9c313c8fba72777234193a44dce431a8..9f6714cc458bd5573ba3ee208156bad826a7e64e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt @@ -49,8 +49,8 @@ internal class RoomEncryptorsStore @Inject constructor( } else { val alg: IMXEncrypting? = when (cryptoStore.getRoomAlgorithm(roomId)) { MXCRYPTO_ALGORITHM_MEGOLM -> megolmEncryptionFactory.create(roomId) - MXCRYPTO_ALGORITHM_OLM -> olmEncryptionFactory.create(roomId) - else -> null + MXCRYPTO_ALGORITHM_OLM -> olmEncryptionFactory.create(roomId) + else -> null } alg?.let { roomEncryptors.put(roomId, it) } return@synchronized alg diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt index 6fb6914206f9e97000915ab0262117c435278c27..a79e1a89012a7e3d4b02aa18825111cfb6047f27 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt @@ -150,14 +150,14 @@ internal class SecretShareManager @Inject constructor( // we can share the secret val secretValue = when (secretName) { - MASTER_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.master + MASTER_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.master SELF_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.selfSigned USER_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.user KEYBACKUP_SECRET_SSSS_NAME -> cryptoStore.getKeyBackupRecoveryKeyInfo()?.recoveryKey ?.let { extractCurveKeyFromRecoveryKey(it)?.toBase64NoPadding() } - else -> null + else -> null } if (secretValue == null) { Timber.tag(loggerTag.value) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt index c728f1b6827a427dda5124d3398b9615b0b5bce2..c263192fee5e0a5929d331e30d131a9038e4e656 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt @@ -39,7 +39,8 @@ private val loggerTag = LoggerTag("EnsureOlmSessionsForDevicesAction", LoggerTag internal class EnsureOlmSessionsForDevicesAction @Inject constructor( private val olmDevice: MXOlmDevice, private val coroutineDispatchers: MatrixCoroutineDispatchers, - private val oneTimeKeysForUsersDeviceTask: ClaimOneTimeKeysForUsersDeviceTask) { + private val oneTimeKeysForUsersDeviceTask: ClaimOneTimeKeysForUsersDeviceTask +) { private val ensureMutex = Mutex() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt index fc211537a6872f02dece4f11d9ce77e82df9ec99..da0952466857a6f0712ee6008d171fad9365c266 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt @@ -23,13 +23,15 @@ import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import timber.log.Timber import javax.inject.Inject -internal class EnsureOlmSessionsForUsersAction @Inject constructor(private val olmDevice: MXOlmDevice, - private val cryptoStore: IMXCryptoStore, - private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction) { +internal class EnsureOlmSessionsForUsersAction @Inject constructor( + private val olmDevice: MXOlmDevice, + private val cryptoStore: IMXCryptoStore, + private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction +) { /** * Try to make sure we have established olm sessions for the given users. - * @param users a list of user ids. + * @param users a list of user ids. */ suspend fun handle(users: List<String>): MXUsersDevicesMap<MXOlmSessionResult> { Timber.v("## ensureOlmSessionsForUsers() : ensureOlmSessionsForUsers $users") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt index 22c4e59b1899dd3f23e74cf17ad2019f0df034e7..f6ab96aee68033c95460b670ecc194b403003e89 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt @@ -33,11 +33,12 @@ import javax.inject.Inject private val loggerTag = LoggerTag("MegolmSessionDataImporter", LoggerTag.CRYPTO) -internal class MegolmSessionDataImporter @Inject constructor(private val olmDevice: MXOlmDevice, - private val roomDecryptorProvider: RoomDecryptorProvider, - private val outgoingKeyRequestManager: OutgoingKeyRequestManager, - private val cryptoStore: IMXCryptoStore, - private val clock: Clock, +internal class MegolmSessionDataImporter @Inject constructor( + private val olmDevice: MXOlmDevice, + private val roomDecryptorProvider: RoomDecryptorProvider, + private val outgoingKeyRequestManager: OutgoingKeyRequestManager, + private val cryptoStore: IMXCryptoStore, + private val clock: Clock, ) { /** @@ -45,14 +46,16 @@ internal class MegolmSessionDataImporter @Inject constructor(private val olmDevi * Must be call on the crypto coroutine thread * * @param megolmSessionsData megolm sessions. - * @param fromBackup true if the imported keys are already backed up on the server. - * @param progressListener the progress listener + * @param fromBackup true if the imported keys are already backed up on the server. + * @param progressListener the progress listener * @return import room keys result */ @WorkerThread - fun handle(megolmSessionsData: List<MegolmSessionData>, - fromBackup: Boolean, - progressListener: ProgressListener?): ImportRoomKeysResult { + fun handle( + megolmSessionsData: List<MegolmSessionData>, + fromBackup: Boolean, + progressListener: ProgressListener? + ): ImportRoomKeysResult { val t0 = clock.epochMillis() val totalNumbersOfKeys = megolmSessionsData.size diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MessageEncrypter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MessageEncrypter.kt index 9bbbab4992a4b1bb2bb676b3edbe1227e7c61419..eff21328204cd71bafec416d76ab5035aef6d321 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MessageEncrypter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MessageEncrypter.kt @@ -36,13 +36,14 @@ internal class MessageEncrypter @Inject constructor( private val userId: String, @DeviceId private val deviceId: String?, - private val olmDevice: MXOlmDevice) { + private val olmDevice: MXOlmDevice +) { /** * Encrypt an event payload for a list of devices. * This method must be called from the getCryptoHandler() thread. * * @param payloadFields fields to include in the encrypted payload. - * @param deviceInfos list of device infos to encrypt for. + * @param deviceInfos list of device infos to encrypt for. * @return the content for an m.room.encrypted event. */ suspend fun encryptMessage(payloadFields: Content, deviceInfos: List<CryptoDeviceInfo>): EncryptedMessage { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/SetDeviceVerificationAction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/SetDeviceVerificationAction.kt index 60181138fb976f820119caecfc9edcd8570c3acb..6028b1a5a2a4ca6de7172a9774292149fa2dec2c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/SetDeviceVerificationAction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/SetDeviceVerificationAction.kt @@ -26,7 +26,8 @@ import javax.inject.Inject internal class SetDeviceVerificationAction @Inject constructor( private val cryptoStore: IMXCryptoStore, @UserId private val userId: String, - private val defaultKeysBackupService: DefaultKeysBackupService) { + private val defaultKeysBackupService: DefaultKeysBackupService +) { fun handle(trustLevel: DeviceTrustLevel, userId: String, deviceId: String) { val device = cryptoStore.getUserDevice(userId, deviceId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt index 34006ecfde5910ff4b5684a4ec769ef0609a41e5..6847a463690c369774fd09d6efb7bf0c52bdabc4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt @@ -29,7 +29,7 @@ internal interface IMXDecrypting { /** * Decrypt an event. * - * @param event the raw event. + * @param event the raw event. * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack. * @return the decryption information, or an error */ @@ -40,6 +40,7 @@ internal interface IMXDecrypting { * Handle a key event. * * @param event the key event. + * @param defaultKeysBackupService the keys backup service */ fun onRoomKeyEvent(event: Event, defaultKeysBackupService: DefaultKeysBackupService) {} } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt index 1d8412020876990c6631da60b05743409f676f4d..73ce5a5004b10ca227b8d50362fe6881546dbb69 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt @@ -27,8 +27,8 @@ internal interface IMXEncrypting { * Encrypt an event content according to the configuration of the room. * * @param eventContent the content of the event. - * @param eventType the type of the event. - * @param userIds the room members the event will be sent to. + * @param eventType the type of the event. + * @param userIds the room members the event will be sent to. * @return the encrypted content */ suspend fun encryptEventContent(eventContent: Content, eventType: String, userIds: List<String>): Content diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXGroupEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXGroupEncryption.kt index 6f488def0af0d366df361e76999efcfa1e0f637f..9ec78f37cfee18542fb3a25da3917896b0a8f445 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXGroupEncryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXGroupEncryption.kt @@ -38,15 +38,17 @@ internal interface IMXGroupEncryption { * Re-shares a session key with devices if the key has already been * sent to them. * - * @param sessionId The id of the outbound session to share. + * @param groupSessionId The id of the outbound session to share. * @param userId The id of the user who owns the target device. * @param deviceId The id of the target device. * @param senderKey The key of the originating device for the session. * * @return true in case of success */ - suspend fun reshareKey(groupSessionId: String, - userId: String, - deviceId: String, - senderKey: String): Boolean + suspend fun reshareKey( + groupSessionId: String, + userId: String, + deviceId: String, + senderKey: String + ): Boolean } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt index 8321b73b758c2baa34dc780cddf5bbc22199b1cb..141d6f74cd0b23525356af59790b459dbeceba3e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt @@ -78,6 +78,7 @@ internal class MXMegolmDecryption( encryptedEventContent.ciphertext, event.roomId, timeline, + eventId = event.eventId.orEmpty(), encryptedEventContent.sessionId, encryptedEventContent.senderKey ) @@ -148,7 +149,8 @@ internal class MXMegolmDecryption( throw MXCryptoError.Base( MXCryptoError.ErrorType.KEYS_WITHHELD, withHeldInfo.code?.value ?: "", - withHeldInfo.reason) + withHeldInfo.reason + ) } if (requestKeysOnFail) { @@ -176,6 +178,7 @@ internal class MXMegolmDecryption( * Handle a key event. * * @param event the key event. + * @param defaultKeysBackupService the keys backup service */ override fun onRoomKeyEvent(event: Event, defaultKeysBackupService: DefaultKeysBackupService) { Timber.tag(loggerTag.value).v("onRoomKeyEvent()") @@ -247,9 +250,9 @@ internal class MXMegolmDecryption( ) when (addSessionResult) { - is MXOlmDevice.AddSessionResult.Imported -> addSessionResult.ratchetIndex + is MXOlmDevice.AddSessionResult.Imported -> addSessionResult.ratchetIndex is MXOlmDevice.AddSessionResult.NotImportedHigherIndex -> addSessionResult.newIndex - else -> null + else -> null }?.let { index -> if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) { val fromDevice = (event.content?.get("sender_key") as? String)?.let { senderDeviceIdentityKey -> @@ -266,7 +269,8 @@ internal class MXMegolmDecryption( senderKey = senderKey, fromIndex = index, fromDevice = fromDevice, - event = event) + event = event + ) cryptoStore.saveIncomingForwardKeyAuditTrail( roomId = roomKeyContent.roomId, @@ -275,7 +279,8 @@ internal class MXMegolmDecryption( algorithm = roomKeyContent.algorithm ?: "", userId = event.senderId ?: "", deviceId = fromDevice ?: "", - chainIndex = index.toLong()) + chainIndex = index.toLong() + ) // The index is used to decide if we cancel sent request or if we wait for a better key outgoingKeyRequestManager.postCancelRequestForSessionIfNeeded(roomKeyContent.sessionId, roomKeyContent.roomId, senderKey, index) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt index 096773a9594772d050829bf9cf7a62a9d073d844..81a6fb28c06e4fc30bdc24c7b5f62fbc5995c1c0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt @@ -35,6 +35,7 @@ internal class MXMegolmDecryptionFactory @Inject constructor( olmDevice, outgoingKeyRequestManager, cryptoStore, - eventsManager) + eventsManager + ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt index 79e907945fc9e403590f2377097aad29857e700d..7bfbae6edf5ab194de33dec1054e3fef5b3c2d2b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt @@ -84,9 +84,11 @@ internal class MXMegolmEncryption( private var sessionRotationPeriodMsgs: Int = 100 private var sessionRotationPeriodMs: Int = 7 * 24 * 3600 * 1000 - override suspend fun encryptEventContent(eventContent: Content, - eventType: String, - userIds: List<String>): Content { + override suspend fun encryptEventContent( + eventContent: Content, + eventType: String, + userIds: List<String> + ): Content { val ts = clock.epochMillis() Timber.tag(loggerTag.value).v("encryptEventContent : getDevicesInRoom") val devices = getDevicesInRoom(userIds) @@ -198,11 +200,13 @@ internal class MXMegolmEncryption( /** * Share the device key to a list of users. * - * @param session the session info + * @param session the session info * @param devicesByUsers the devices map */ - private suspend fun shareKey(session: MXOutboundSessionInfo, - devicesByUsers: Map<String, List<CryptoDeviceInfo>>) { + private suspend fun shareKey( + session: MXOutboundSessionInfo, + devicesByUsers: Map<String, List<CryptoDeviceInfo>> + ) { // nothing to send, the task is done if (devicesByUsers.isEmpty()) { Timber.tag(loggerTag.value).v("shareKey() : nothing more to do") @@ -227,11 +231,13 @@ internal class MXMegolmEncryption( /** * Share the device keys of a an user. * - * @param session the session info + * @param session the session info * @param devicesByUser the devices map */ - private suspend fun shareUserDevicesKey(session: MXOutboundSessionInfo, - devicesByUser: Map<String, List<CryptoDeviceInfo>>) { + private suspend fun shareUserDevicesKey( + session: MXOutboundSessionInfo, + devicesByUser: Map<String, List<CryptoDeviceInfo>> + ) { val sessionKey = olmDevice.getSessionKey(session.sessionId) val chainIndex = olmDevice.getMessageIndex(session.sessionId) @@ -321,10 +327,12 @@ internal class MXMegolmEncryption( } } - private suspend fun notifyKeyWithHeld(targets: List<UserDevice>, - sessionId: String, - senderKey: String?, - code: WithHeldCode) { + private suspend fun notifyKeyWithHeld( + targets: List<UserDevice>, + sessionId: String, + senderKey: String?, + code: WithHeldCode + ) { Timber.tag(loggerTag.value).d( "notifyKeyWithHeld() :sending withheld for session:$sessionId and code $code to" + " ${targets.joinToString { "${it.userId}|${it.deviceId}" }}" @@ -387,7 +395,7 @@ internal class MXMegolmEncryption( * Get the list of devices which can encrypt data to. * This method must be called in getDecryptingThreadHandler() thread. * - * @param userIds the user ids whose devices must be checked. + * @param userIds the user ids whose devices must be checked. */ private suspend fun getDevicesInRoom(userIds: List<String>): DeviceInRoomInfo { // We are happy to use a cached version here: we assume that if we already @@ -435,10 +443,12 @@ internal class MXMegolmEncryption( } } - override suspend fun reshareKey(groupSessionId: String, - userId: String, - deviceId: String, - senderKey: String): Boolean { + override suspend fun reshareKey( + groupSessionId: String, + userId: String, + deviceId: String, + senderKey: String + ): Boolean { Timber.tag(loggerTag.value).i("process reshareKey for $groupSessionId to $userId:$deviceId") val deviceInfo = cryptoStore.getUserDevice(userId, deviceId) ?: return false .also { Timber.tag(loggerTag.value).w("reshareKey: Device not found") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt index 61ad345c62ca1b62d3ac399f19ea8d59849b7187..30fd403ce8588c32299d174986088c46676304c1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt @@ -23,7 +23,8 @@ import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore internal class SharedWithHelper( private val roomId: String, private val sessionId: String, - private val cryptoStore: IMXCryptoStore) { + private val cryptoStore: IMXCryptoStore +) { fun sharedWithDevices(): MXUsersDevicesMap<Int> { return cryptoStore.getSharedWithInfo(roomId, sessionId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt index 1e66fe84c96b51135a72e267ae18e0f271468af5..219cadac464f896826fb0b6425322e7f786762f3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt @@ -38,7 +38,8 @@ internal class MXOlmDecryption( // The olm device interface private val olmDevice: MXOlmDevice, // the matrix userId - private val userId: String) : + private val userId: String +) : IMXDecrypting { @Throws(MXCryptoError::class) @@ -180,8 +181,8 @@ internal class MXOlmDecryption( /** * Attempt to decrypt an Olm message. * + * @param message message object, with 'type' and 'body' fields. * @param theirDeviceIdentityKey the Curve25519 identity key of the sender. - * @param message message object, with 'type' and 'body' fields. * @return payload, if decrypted successfully. */ private suspend fun decryptMessage(message: JsonDict, theirDeviceIdentityKey: String): String? { @@ -190,9 +191,9 @@ internal class MXOlmDecryption( val messageBody = message["body"] as? String ?: return null val messageType = when (val typeAsVoid = message["type"]) { is Double -> typeAsVoid.toInt() - is Int -> typeAsVoid - is Long -> typeAsVoid.toInt() - else -> return null + is Int -> typeAsVoid + is Long -> typeAsVoid.toInt() + else -> return null } // Try each session in turn diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt index d5c5e85e41a1e37ed5ff6874fb040f47666edb4b..a50ac8ca8a82fe440c79490ca8e2c1bd0cfe9827 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt @@ -20,8 +20,10 @@ import org.matrix.android.sdk.internal.crypto.MXOlmDevice import org.matrix.android.sdk.internal.di.UserId import javax.inject.Inject -internal class MXOlmDecryptionFactory @Inject constructor(private val olmDevice: MXOlmDevice, - @UserId private val userId: String) { +internal class MXOlmDecryptionFactory @Inject constructor( + private val olmDevice: MXOlmDevice, + @UserId private val userId: String +) { fun create(): MXOlmDecryption { return MXOlmDecryption( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryption.kt index 3c9706abe18e31ddadeb5c39cf9b8332cf65c895..fb70e23b03c66edf3d87587681ca0abbbfb02c14 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryption.kt @@ -32,7 +32,8 @@ internal class MXOlmEncryption( private val cryptoStore: IMXCryptoStore, private val messageEncrypter: MessageEncrypter, private val deviceListManager: DeviceListManager, - private val ensureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction) : + private val ensureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction +) : IMXEncrypting { override suspend fun encryptEventContent(eventContent: Content, eventType: String, userIds: List<String>): Content { @@ -70,7 +71,7 @@ internal class MXOlmEncryption( /** * Ensure that the session. * - * @param users the user ids list + * @param users the user ids list */ private suspend fun ensureSession(users: List<String>) { deviceListManager.downloadKeys(users, false) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt index 44e55900e4ada7db382ba541a5c51989a72a3d68..012886203ec19015558deba7158c1859c5b48a9a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt @@ -24,12 +24,14 @@ import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import javax.inject.Inject -internal class MXOlmEncryptionFactory @Inject constructor(private val olmDevice: MXOlmDevice, - private val cryptoStore: IMXCryptoStore, - private val messageEncrypter: MessageEncrypter, - private val deviceListManager: DeviceListManager, - private val coroutineDispatchers: MatrixCoroutineDispatchers, - private val ensureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction) { +internal class MXOlmEncryptionFactory @Inject constructor( + private val olmDevice: MXOlmDevice, + private val cryptoStore: IMXCryptoStore, + private val messageEncrypter: MessageEncrypter, + private val deviceListManager: DeviceListManager, + private val coroutineDispatchers: MatrixCoroutineDispatchers, + private val ensureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction +) { fun create(roomId: String): MXOlmEncryption { return MXOlmEncryption( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/api/CryptoApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/api/CryptoApi.kt index f21f5e05e1416d081cdf9e0d54bba9e3d9e1bed9..d5a8bdfd7cb62f17b4be13f66a34b18a7c6df820 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/api/CryptoApi.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/api/CryptoApi.kt @@ -103,7 +103,7 @@ internal interface CryptoApi { * Claim one-time keys. * Doc: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-keys-claim * - * @param params the params. + * @param body the Json body. */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "keys/claim") suspend fun claimOneTimeKeysForUsersDevices(@Body body: KeysClaimBody): KeysClaimResponse @@ -112,36 +112,42 @@ internal interface CryptoApi { * Send an event to a specific list of devices * Doc: https://matrix.org/docs/spec/client_server/r0.4.0.html#put-matrix-client-r0-sendtodevice-eventtype-txnid * - * @param eventType the type of event to send + * @param eventType the type of event to send * @param transactionId the transaction ID for this event - * @param body the body + * @param body the body */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "sendToDevice/{eventType}/{txnId}") - suspend fun sendToDevice(@Path("eventType") eventType: String, - @Path("txnId") transactionId: String, - @Body body: SendToDeviceBody) + suspend fun sendToDevice( + @Path("eventType") eventType: String, + @Path("txnId") transactionId: String, + @Body body: SendToDeviceBody + ) /** * Delete a device. * Doc: https://matrix.org/docs/spec/client_server/r0.4.0.html#delete-matrix-client-r0-devices-deviceid * * @param deviceId the device id - * @param params the deletion parameters + * @param params the deletion parameters */ @HTTP(path = NetworkConstants.URI_API_PREFIX_PATH_R0 + "devices/{device_id}", method = "DELETE", hasBody = true) - suspend fun deleteDevice(@Path("device_id") deviceId: String, - @Body params: DeleteDeviceParams) + suspend fun deleteDevice( + @Path("device_id") deviceId: String, + @Body params: DeleteDeviceParams + ) /** * Update the device information. * Doc: https://matrix.org/docs/spec/client_server/r0.4.0.html#put-matrix-client-r0-devices-deviceid * * @param deviceId the device id - * @param params the params + * @param params the params */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "devices/{device_id}") - suspend fun updateDeviceInfo(@Path("device_id") deviceId: String, - @Body params: UpdateDeviceInfoBody) + suspend fun updateDeviceInfo( + @Path("device_id") deviceId: String, + @Body params: UpdateDeviceInfoBody + ) /** * Get the update devices list from two sync token. @@ -151,6 +157,8 @@ internal interface CryptoApi { * @param newToken the up-to token. */ @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "keys/changes") - suspend fun getKeyChanges(@Query("from") oldToken: String, - @Query("to") newToken: String): KeyChangesResponse + suspend fun getKeyChanges( + @Query("from") oldToken: String, + @Query("to") newToken: String + ): KeyChangesResponse } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt index b4cbd15109b5ca457ee426472dc50f7a319aa69c..37c8e755ff81632a034db67348ea448afac54f9e 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt @@ -41,10 +41,12 @@ internal object MXEncryptedAttachments { private const val SECRET_KEY_SPEC_ALGORITHM = "AES" private const val MESSAGE_DIGEST_ALGORITHM = "SHA-256" - fun encrypt(clearStream: InputStream, - outputFile: File, - clock: Clock, - progress: ((current: Int, total: Int) -> Unit)): EncryptedFileInfo { + fun encrypt( + clearStream: InputStream, + outputFile: File, + clock: Clock, + progress: ((current: Int, total: Int) -> Unit) + ): EncryptedFileInfo { val t0 = clock.epochMillis() val secureRandom = SecureRandom() val initVectorBytes = ByteArray(16) { 0.toByte() } @@ -159,6 +161,7 @@ internal object MXEncryptedAttachments { * Encrypt an attachment stream. * DO NOT USE for big files, it will load all in memory * @param attachmentStream the attachment stream. Will be closed after this method call. + * @param clock a clock to retrieve current time * @return the encryption file info */ fun encryptAttachment(attachmentStream: InputStream, clock: Clock): EncryptionResult { @@ -231,13 +234,15 @@ internal object MXEncryptedAttachments { * * @param attachmentStream the attachment stream. Will be closed after this method call. * @param elementToDecrypt the elementToDecrypt info - * @param outputStream the outputStream where the decrypted attachment will be write. + * @param outputStream the outputStream where the decrypted attachment will be write. + * @param clock a clock to retrieve current time * @return true in case of success, false in case of error */ - fun decryptAttachment(attachmentStream: InputStream?, - elementToDecrypt: ElementToDecrypt?, - outputStream: OutputStream, - clock: Clock + fun decryptAttachment( + attachmentStream: InputStream?, + elementToDecrypt: ElementToDecrypt?, + outputStream: OutputStream, + clock: Clock ): Boolean { // sanity checks if (null == attachmentStream || elementToDecrypt == null) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt index 4fa355cd2a787511b5463d9abf70e526a35a3376..3218b9994839f72d5d01c150881bf8928b335f16 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt @@ -53,13 +53,13 @@ internal class CrossSigningOlm @Inject constructor( fun signObject(type: KeyType, strToSign: String): Map<String, String> { val myKeys = cryptoStore.getMyCrossSigningInfo() val pubKey = when (type) { - KeyType.SELF -> myKeys?.selfSigningKey() - KeyType.USER -> myKeys?.userKey() + KeyType.SELF -> myKeys?.selfSigningKey() + KeyType.USER -> myKeys?.userKey() KeyType.MASTER -> myKeys?.masterKey() }?.unpaddedBase64PublicKey val pkSigning = when (type) { - KeyType.SELF -> selfSigningPkSigning - KeyType.USER -> userPkSigning + KeyType.SELF -> selfSigningPkSigning + KeyType.USER -> userPkSigning KeyType.MASTER -> masterPkSigning } if (pubKey == null || pkSigning == null) { @@ -76,8 +76,8 @@ internal class CrossSigningOlm @Inject constructor( ?: throw NoSuchElementException("Cross Signing not configured") val myUserID = myKeys.userId val pubKey = when (type) { - KeyType.SELF -> myKeys.selfSigningKey() - KeyType.USER -> myKeys.userKey() + KeyType.SELF -> myKeys.selfSigningKey() + KeyType.USER -> myKeys.userKey() KeyType.MASTER -> myKeys.masterKey() }?.unpaddedBase64PublicKey ?: throw NoSuchElementException("Cross Signing not configured") val signaturesMadeByMyKey = signatures[myUserID] // Signatures made by me diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt index 6c198abc2ed7db270b448dca000cb632468f3095..e466def1a164ea9bd858d93936850e6d80173db7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt @@ -261,9 +261,10 @@ internal class DefaultCrossSigningService @Inject constructor( } } - override fun checkTrustFromPrivateKeys(masterKeyPrivateKey: String?, - uskKeyPrivateKey: String?, - sskPrivateKey: String? + override fun checkTrustFromPrivateKeys( + masterKeyPrivateKey: String?, + uskKeyPrivateKey: String?, + sskPrivateKey: String? ): UserTrustResult { val mxCrossSigningInfo = getMyCrossSigningKeys() ?: return UserTrustResult.CrossSigningNotConfigured(userId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt index 74f0f5745d39d0745b923ef6f177b392e86f1dc6..f1dc060e10e6b21ce00d4876512c8483ec5f627c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt @@ -149,7 +149,7 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses val trusts = otherInfos.mapValues { entry -> when (entry.key) { myUserId -> myTrustResult - else -> { + else -> { crossSigningService.checkOtherMSKTrusted(myCrossSigningInfo, entry.value).also { Timber.v("## CrossSigning - user:${entry.key} result:$it") } @@ -276,10 +276,12 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses } } - private fun computeRoomShield(myCrossSigningInfo: MXCrossSigningInfo?, - cryptoRealm: Realm, - activeMemberUserIds: List<String>, - roomSummaryEntity: RoomSummaryEntity): RoomEncryptionTrustLevel { + private fun computeRoomShield( + myCrossSigningInfo: MXCrossSigningInfo?, + cryptoRealm: Realm, + activeMemberUserIds: List<String>, + roomSummaryEntity: RoomSummaryEntity + ): RoomEncryptionTrustLevel { Timber.v("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} -> ${activeMemberUserIds.logLimit()}") // The set of “all users†depends on the type of room: // For regular / topic rooms which have more than 2 members (including yourself) are considered when decorating a room diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt index 5ea4695da29b4bcf73a372cc338c6b88909db9b2..5eaa106af3cc732c38953816dd1c94f505aa97ca 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt @@ -137,17 +137,11 @@ internal class DefaultKeysBackupService @Inject constructor( private var keysBackupStateListener: KeysBackupStateListener? = null - override val isEnabled: Boolean - get() = keysBackupStateManager.isEnabled + override fun isEnabled(): Boolean = keysBackupStateManager.isEnabled - override val isStucked: Boolean - get() = keysBackupStateManager.isStucked + override fun isStuck(): Boolean = keysBackupStateManager.isStuck - override val state: KeysBackupState - get() = keysBackupStateManager.state - - override val currentBackupVersion: String? - get() = keysBackupVersion?.version + override fun getState(): KeysBackupState = keysBackupStateManager.state override fun addListener(listener: KeysBackupStateListener) { keysBackupStateManager.addListener(listener) @@ -157,9 +151,11 @@ internal class DefaultKeysBackupService @Inject constructor( keysBackupStateManager.removeListener(listener) } - override fun prepareKeysBackupVersion(password: String?, - progressListener: ProgressListener?, - callback: MatrixCallback<MegolmBackupCreationInfo>) { + override fun prepareKeysBackupVersion( + password: String?, + progressListener: ProgressListener?, + callback: MatrixCallback<MegolmBackupCreationInfo> + ) { cryptoCoroutineScope.launch(coroutineDispatchers.io) { try { val olmPkDecryption = OlmPkDecryption() @@ -233,8 +229,10 @@ internal class DefaultKeysBackupService @Inject constructor( } } - override fun createKeysBackupVersion(keysBackupCreationInfo: MegolmBackupCreationInfo, - callback: MatrixCallback<KeysVersion>) { + override fun createKeysBackupVersion( + keysBackupCreationInfo: MegolmBackupCreationInfo, + callback: MatrixCallback<KeysVersion> + ) { @Suppress("UNCHECKED_CAST") val createKeysBackupVersionBody = CreateKeysBackupVersionBody( algorithm = keysBackupCreationInfo.algorithm, @@ -291,7 +289,7 @@ internal class DefaultKeysBackupService @Inject constructor( this.callback = object : MatrixCallback<Unit> { private fun eventuallyRestartBackup() { // Do not stay in KeysBackupState.Unknown but check what is available on the homeserver - if (state == KeysBackupState.Unknown) { + if (getState() == KeysBackupState.Unknown) { checkAndStartKeysBackup() } } @@ -324,7 +322,7 @@ internal class DefaultKeysBackupService @Inject constructor( // val hashServer = keysBackupData?.backupLastServerHash return when { - totalNumberOfKeysLocally < totalNumberOfKeysServer -> { + totalNumberOfKeysLocally < totalNumberOfKeysServer -> { // Server contains more keys than this device true } @@ -333,7 +331,7 @@ internal class DefaultKeysBackupService @Inject constructor( // TODO We have not found any algorithm to determine if a restore is recommended here. Return false for the moment false } - else -> false + else -> false } } @@ -345,9 +343,11 @@ internal class DefaultKeysBackupService @Inject constructor( return cryptoStore.inboundGroupSessionsCount(true) } - override fun backupAllGroupSessions(progressListener: ProgressListener?, - callback: MatrixCallback<Unit>?) { - if (!isEnabled || backupOlmPkEncryption == null || keysBackupVersion == null) { + override fun backupAllGroupSessions( + progressListener: ProgressListener?, + callback: MatrixCallback<Unit>? + ) { + if (!isEnabled() || backupOlmPkEncryption == null || keysBackupVersion == null) { callback?.onFailure(Throwable("Backup not enabled")) return } @@ -383,7 +383,7 @@ internal class DefaultKeysBackupService @Inject constructor( } // If backup is finished, notify the main listener - if (state === KeysBackupState.ReadyToBackUp) { + if (getState() === KeysBackupState.ReadyToBackUp) { backupAllGroupSessionsCallback?.onSuccess(Unit) resetBackupAllGroupSessionsListeners() } @@ -397,8 +397,10 @@ internal class DefaultKeysBackupService @Inject constructor( }) } - override fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult, - callback: MatrixCallback<KeysBackupVersionTrust>) { + override fun getKeysBackupTrust( + keysBackupVersion: KeysVersionResult, + callback: MatrixCallback<KeysBackupVersionTrust> + ) { // TODO Validate with François that this is correct object : Task<KeysVersionResult, KeysBackupVersionTrust> { override suspend fun execute(params: KeysVersionResult): KeysBackupVersionTrust { @@ -505,9 +507,11 @@ internal class DefaultKeysBackupService @Inject constructor( ) } - override fun trustKeysBackupVersion(keysBackupVersion: KeysVersionResult, - trust: Boolean, - callback: MatrixCallback<Unit>) { + override fun trustKeysBackupVersion( + keysBackupVersion: KeysVersionResult, + trust: Boolean, + callback: MatrixCallback<Unit> + ) { Timber.v("trustKeyBackupVersion: $trust, version ${keysBackupVersion.version}") // Get auth data to update it @@ -589,9 +593,11 @@ internal class DefaultKeysBackupService @Inject constructor( } } - override fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult, - recoveryKey: String, - callback: MatrixCallback<Unit>) { + override fun trustKeysBackupVersionWithRecoveryKey( + keysBackupVersion: KeysVersionResult, + recoveryKey: String, + callback: MatrixCallback<Unit> + ) { Timber.v("trustKeysBackupVersionWithRecoveryKey: version ${keysBackupVersion.version}") cryptoCoroutineScope.launch(coroutineDispatchers.io) { @@ -608,9 +614,11 @@ internal class DefaultKeysBackupService @Inject constructor( } } - override fun trustKeysBackupVersionWithPassphrase(keysBackupVersion: KeysVersionResult, - password: String, - callback: MatrixCallback<Unit>) { + override fun trustKeysBackupVersionWithPassphrase( + keysBackupVersion: KeysVersionResult, + password: String, + callback: MatrixCallback<Unit> + ) { Timber.v("trustKeysBackupVersionWithPassphrase: version ${keysBackupVersion.version}") cryptoCoroutineScope.launch(coroutineDispatchers.io) { @@ -628,7 +636,7 @@ internal class DefaultKeysBackupService @Inject constructor( } } - override fun onSecretKeyGossip(secret: String) { + fun onSecretKeyGossip(secret: String) { Timber.i("## CrossSigning - onSecretKeyGossip") cryptoCoroutineScope.launch(coroutineDispatchers.io) { @@ -707,12 +715,14 @@ internal class DefaultKeysBackupService @Inject constructor( progressListener.onProgress(backedUpKeys, total) } - override fun restoreKeysWithRecoveryKey(keysVersionResult: KeysVersionResult, - recoveryKey: String, - roomId: String?, - sessionId: String?, - stepProgressListener: StepProgressListener?, - callback: MatrixCallback<ImportRoomKeysResult>) { + override fun restoreKeysWithRecoveryKey( + keysVersionResult: KeysVersionResult, + recoveryKey: String, + roomId: String?, + sessionId: String?, + stepProgressListener: StepProgressListener?, + callback: MatrixCallback<ImportRoomKeysResult> + ) { Timber.v("restoreKeysWithRecoveryKey: From backup version: ${keysVersionResult.version}") cryptoCoroutineScope.launch(coroutineDispatchers.io) { @@ -806,12 +816,14 @@ internal class DefaultKeysBackupService @Inject constructor( } } - override fun restoreKeyBackupWithPassword(keysBackupVersion: KeysVersionResult, - password: String, - roomId: String?, - sessionId: String?, - stepProgressListener: StepProgressListener?, - callback: MatrixCallback<ImportRoomKeysResult>) { + override fun restoreKeyBackupWithPassword( + keysBackupVersion: KeysVersionResult, + password: String, + roomId: String?, + sessionId: String?, + stepProgressListener: StepProgressListener?, + callback: MatrixCallback<ImportRoomKeysResult> + ) { Timber.v("[MXKeyBackup] restoreKeyBackup with password: From backup version: ${keysBackupVersion.version}") cryptoCoroutineScope.launch(coroutineDispatchers.io) { @@ -859,9 +871,11 @@ internal class DefaultKeysBackupService @Inject constructor( * Same method as [RoomKeysRestClient.getRoomKey] except that it accepts nullable * parameters and always returns a KeysBackupData object through the Callback. */ - private suspend fun getKeys(sessionId: String?, - roomId: String?, - version: String): KeysBackupData { + private suspend fun getKeys( + sessionId: String?, + roomId: String?, + version: String + ): KeysBackupData { return if (roomId != null && sessionId != null) { // Get key for the room and for the session val data = getRoomSessionDataTask.execute(GetRoomSessionDataTask.Params(roomId, sessionId, version)) @@ -915,12 +929,12 @@ internal class DefaultKeysBackupService @Inject constructor( */ fun maybeBackupKeys() { when { - isStucked -> { + isStuck() -> { // If not already done, or in error case, check for a valid backup version on the homeserver. // If there is one, maybeBackupKeys will be called again. checkAndStartKeysBackup() } - state == KeysBackupState.ReadyToBackUp -> { + getState() == KeysBackupState.ReadyToBackUp -> { keysBackupStateManager.state = KeysBackupState.WillBackUp // Wait between 0 and 10 seconds, to avoid backup requests from @@ -933,14 +947,16 @@ internal class DefaultKeysBackupService @Inject constructor( uiHandler.post { backupKeys() } } } - else -> { - Timber.v("maybeBackupKeys: Skip it because state: $state") + else -> { + Timber.v("maybeBackupKeys: Skip it because state: ${getState()}") } } } - override fun getVersion(version: String, - callback: MatrixCallback<KeysVersionResult?>) { + override fun getVersion( + version: String, + callback: MatrixCallback<KeysVersionResult?> + ) { getKeysBackupVersionTask .configureWith(version) { this.callback = object : MatrixCallback<KeysVersionResult> { @@ -976,7 +992,7 @@ internal class DefaultKeysBackupService @Inject constructor( override fun onSuccess(data: KeysBackupLastVersionResult) { val localBackupVersion = keysBackupVersion?.version when (data) { - KeysBackupLastVersionResult.NoKeysBackup -> { + KeysBackupLastVersionResult.NoKeysBackup -> { if (localBackupVersion == null) { // No backup on the server, and backup is not active callback.onSuccess(true) @@ -1018,9 +1034,9 @@ internal class DefaultKeysBackupService @Inject constructor( } override fun checkAndStartKeysBackup() { - if (!isStucked) { + if (!isStuck()) { // Try to start or restart the backup only if it is in unknown or bad state - Timber.w("checkAndStartKeysBackup: invalid state: $state") + Timber.w("checkAndStartKeysBackup: invalid state: ${getState()}") return } @@ -1105,6 +1121,7 @@ internal class DefaultKeysBackupService @Inject constructor( * * @param password the password. * @param keysBackupData the backup and its auth data. + * @param progressListener listener to track progress * * @return the recovery key if successful, null in other cases */ @@ -1178,10 +1195,12 @@ internal class DefaultKeysBackupService @Inject constructor( } } - override fun computePrivateKey(passphrase: String, - privateKeySalt: String, - privateKeyIterations: Int, - progressListener: ProgressListener): ByteArray { + override fun computePrivateKey( + passphrase: String, + privateKeySalt: String, + privateKeyIterations: Int, + progressListener: ProgressListener + ): ByteArray { return deriveKey(passphrase, privateKeySalt, privateKeyIterations, progressListener) } @@ -1258,16 +1277,16 @@ internal class DefaultKeysBackupService @Inject constructor( Timber.v("backupKeys") // Sanity check, as this method can be called after a delay, the state may have change during the delay - if (!isEnabled || backupOlmPkEncryption == null || keysBackupVersion == null) { + if (!isEnabled() || backupOlmPkEncryption == null || keysBackupVersion == null) { Timber.v("backupKeys: Invalid configuration") backupAllGroupSessionsCallback?.onFailure(IllegalStateException("Invalid configuration")) resetBackupAllGroupSessionsListeners() return } - if (state === KeysBackupState.BackingUp) { + if (getState() === KeysBackupState.BackingUp) { // Do nothing if we are already backing up - Timber.v("backupKeys: Invalid state: $state") + Timber.v("backupKeys: Invalid state: ${getState()}") return } @@ -1359,7 +1378,7 @@ internal class DefaultKeysBackupService @Inject constructor( // Do not stay in KeysBackupState.WrongBackUpVersion but check what is available on the homeserver checkAndStartKeysBackup() } - else -> + else -> // Come back to the ready state so that we will retry on the next received key keysBackupStateManager.state = KeysBackupState.ReadyToBackUp } @@ -1481,8 +1500,10 @@ internal class DefaultKeysBackupService @Inject constructor( get() = cryptoStore @VisibleForTesting - fun createFakeKeysBackupVersion(keysBackupCreationInfo: MegolmBackupCreationInfo, - callback: MatrixCallback<KeysVersion>) { + fun createFakeKeysBackupVersion( + keysBackupCreationInfo: MegolmBackupCreationInfo, + callback: MatrixCallback<KeysVersion> + ) { @Suppress("UNCHECKED_CAST") val createKeysBackupVersionBody = CreateKeysBackupVersionBody( algorithm = keysBackupCreationInfo.algorithm, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPassword.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPassword.kt index d5bab3318094b6485167893b736f7ea2ad579aaa..8560eb5fc13ba44c77963143727f6e2bce3a70de 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPassword.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupPassword.kt @@ -44,12 +44,14 @@ internal data class GeneratePrivateKeyResult( * Compute a private key from a password. * * @param password the password to use. + * @param progressListener a listener to track progress * * @return a {privateKey, salt, iterations} tuple. */ @WorkerThread -internal fun generatePrivateKeyWithPassword(password: String, - progressListener: ProgressListener? +internal fun generatePrivateKeyWithPassword( + password: String, + progressListener: ProgressListener? ): GeneratePrivateKeyResult { val salt = generateSalt() val iterations = DEFAULT_ITERATION @@ -69,10 +71,12 @@ internal fun generatePrivateKeyWithPassword(password: String, * @return a private key. */ @WorkerThread -internal fun retrievePrivateKeyWithPassword(password: String, - salt: String, - iterations: Int, - progressListener: ProgressListener? = null): ByteArray { +internal fun retrievePrivateKeyWithPassword( + password: String, + salt: String, + iterations: Int, + progressListener: ProgressListener? = null +): ByteArray { return deriveKey(password, salt, iterations, progressListener) } @@ -87,10 +91,12 @@ internal fun retrievePrivateKeyWithPassword(password: String, * @return a private key. */ @WorkerThread -internal fun deriveKey(password: String, - salt: String, - iterations: Int, - progressListener: ProgressListener?): ByteArray { +internal fun deriveKey( + password: String, + salt: String, + iterations: Int, + progressListener: ProgressListener? +): ByteArray { // Note: copied and adapted from MXMegolmExportEncryption // based on https://en.wikipedia.org/wiki/PBKDF2 algorithm // it is simpler than the generic algorithm because the expected key length is equal to the mac key length. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupStateManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupStateManager.kt index 78ef958bbff0dae1faa5a617c79d8335f16c721c..0614eceb16e51c845e6b38aa328d0baa02544c63 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupStateManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupStateManager.kt @@ -49,7 +49,7 @@ internal class KeysBackupStateManager(private val uiHandler: Handler) { state == KeysBackupState.BackingUp // True if unknown or bad state - val isStucked: Boolean + val isStuck: Boolean get() = state == KeysBackupState.Unknown || state == KeysBackupState.Disabled || state == KeysBackupState.WrongBackUpVersion || diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/api/RoomKeysApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/api/RoomKeysApi.kt index ea23be59237de603f6c6ce4b649f4b709e3ef22f..48a735018a8dfe3c7cbb931572bd710799ceaf08 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/api/RoomKeysApi.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/api/RoomKeysApi.kt @@ -60,19 +60,21 @@ internal interface RoomKeysApi { * Get information about the given version. * If not supported by the server, an error is returned: {"errcode":"M_NOT_FOUND","error":"No backup found"} * - * @param version version + * @param version version */ @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/version/{version}") suspend fun getKeysBackupVersion(@Path("version") version: String): KeysVersionResult /** * Update information about the given version. - * @param version version + * @param version version * @param updateKeysBackupVersionBody the body */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/version/{version}") - suspend fun updateKeysBackupVersion(@Path("version") version: String, - @Body keysBackupVersionBody: UpdateKeysBackupVersionBody) + suspend fun updateKeysBackupVersion( + @Path("version") version: String, + @Body updateKeysBackupVersionBody: UpdateKeysBackupVersionBody + ) /* ========================================================================================== * Storing keys @@ -87,38 +89,44 @@ internal interface RoomKeysApi { * flag (true is better than false), then by the first_message_index (a lower number is better), and finally by * forwarded_count (a lower number is better). * - * @param roomId the room id - * @param sessionId the session id - * @param version the version of the backup + * @param roomId the room id + * @param sessionId the session id + * @param version the version of the backup * @param keyBackupData the data to send */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys/{roomId}/{sessionId}") - suspend fun storeRoomSessionData(@Path("roomId") roomId: String, - @Path("sessionId") sessionId: String, - @Query("version") version: String, - @Body keyBackupData: KeyBackupData): BackupKeysResult + suspend fun storeRoomSessionData( + @Path("roomId") roomId: String, + @Path("sessionId") sessionId: String, + @Query("version") version: String, + @Body keyBackupData: KeyBackupData + ): BackupKeysResult /** * Store several keys for the given room, using the given backup version. * - * @param roomId the room id - * @param version the version of the backup + * @param roomId the room id + * @param version the version of the backup * @param roomKeysBackupData the data to send */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys/{roomId}") - suspend fun storeRoomSessionsData(@Path("roomId") roomId: String, - @Query("version") version: String, - @Body roomKeysBackupData: RoomKeysBackupData): BackupKeysResult + suspend fun storeRoomSessionsData( + @Path("roomId") roomId: String, + @Query("version") version: String, + @Body roomKeysBackupData: RoomKeysBackupData + ): BackupKeysResult /** * Store several keys, using the given backup version. * - * @param version the version of the backup + * @param version the version of the backup * @param keysBackupData the data to send */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys") - suspend fun storeSessionsData(@Query("version") version: String, - @Body keysBackupData: KeysBackupData): BackupKeysResult + suspend fun storeSessionsData( + @Query("version") version: String, + @Body keysBackupData: KeysBackupData + ): BackupKeysResult /* ========================================================================================== * Retrieving keys @@ -127,29 +135,33 @@ internal interface RoomKeysApi { /** * Retrieve the key for the given session in the given room from the backup. * - * @param roomId the room id + * @param roomId the room id * @param sessionId the session id - * @param version the version of the backup, or empty String to retrieve the last version + * @param version the version of the backup, or empty String to retrieve the last version */ @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys/{roomId}/{sessionId}") - suspend fun getRoomSessionData(@Path("roomId") roomId: String, - @Path("sessionId") sessionId: String, - @Query("version") version: String): KeyBackupData + suspend fun getRoomSessionData( + @Path("roomId") roomId: String, + @Path("sessionId") sessionId: String, + @Query("version") version: String + ): KeyBackupData /** * Retrieve all the keys for the given room from the backup. * - * @param roomId the room id - * @param version the version of the backup, or empty String to retrieve the last version + * @param roomId the room id + * @param version the version of the backup, or empty String to retrieve the last version */ @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys/{roomId}") - suspend fun getRoomSessionsData(@Path("roomId") roomId: String, - @Query("version") version: String): RoomKeysBackupData + suspend fun getRoomSessionsData( + @Path("roomId") roomId: String, + @Query("version") version: String + ): RoomKeysBackupData /** * Retrieve all the keys from the backup. * - * @param version the version of the backup, or empty String to retrieve the last version + * @param version the version of the backup, or empty String to retrieve the last version */ @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys") suspend fun getSessionsData(@Query("version") version: String): KeysBackupData @@ -162,16 +174,20 @@ internal interface RoomKeysApi { * Deletes keys from the backup. */ @DELETE(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys/{roomId}/{sessionId}") - suspend fun deleteRoomSessionData(@Path("roomId") roomId: String, - @Path("sessionId") sessionId: String, - @Query("version") version: String) + suspend fun deleteRoomSessionData( + @Path("roomId") roomId: String, + @Path("sessionId") sessionId: String, + @Query("version") version: String + ) /** * Deletes keys from the backup. */ @DELETE(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "room_keys/keys/{roomId}") - suspend fun deleteRoomSessionsData(@Path("roomId") roomId: String, - @Query("version") version: String) + suspend fun deleteRoomSessionsData( + @Path("roomId") roomId: String, + @Query("version") version: String + ) /** * Deletes keys from the backup. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt index 6bfa56ae8df7cfec01d60f6b474c091314f6fdd8..6b747d19f2f8defb35ea18c911e7afbe568bf9fb 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/MXKey.kt @@ -59,7 +59,7 @@ internal data class MXKey( /** * Returns a signature for an user Id and a signkey. * - * @param userId the user id + * @param userId the user id * @param signkey the sign key * @return the signature */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationAccept.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationAccept.kt index 9fdeda01c9db3093be37c53f78eae27458df7711..85ba1762d3bd62c3bfd899204103f8dea4fb2950 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationAccept.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/KeyVerificationAccept.kt @@ -69,12 +69,14 @@ internal data class KeyVerificationAccept( override fun toSendToDeviceObject() = this companion object : VerificationInfoAcceptFactory { - override fun create(tid: String, - keyAgreementProtocol: String, - hash: String, - commitment: String, - messageAuthenticationCode: String, - shortAuthenticationStrings: List<String>): VerificationInfoAccept { + override fun create( + tid: String, + keyAgreementProtocol: String, + hash: String, + commitment: String, + messageAuthenticationCode: String, + shortAuthenticationStrings: List<String> + ): VerificationInfoAccept { return KeyVerificationAccept( transactionId = tid, keyAgreementProtocol = keyAgreementProtocol, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/VerificationMethodValues.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/VerificationMethodValues.kt index c07434f5861a745b4a3554fb266443764efafd54..afe6191bf7fa55f55e67283d36ea20ab0f00916f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/VerificationMethodValues.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/VerificationMethodValues.kt @@ -28,7 +28,7 @@ internal const val VERIFICATION_METHOD_RECIPROCATE = "m.reciprocate.v1" internal fun VerificationMethod.toValue(): String { return when (this) { - VerificationMethod.SAS -> VERIFICATION_METHOD_SAS + VerificationMethod.SAS -> VERIFICATION_METHOD_SAS VerificationMethod.QR_CODE_SCAN -> VERIFICATION_METHOD_QR_CODE_SCAN VerificationMethod.QR_CODE_SHOW -> VERIFICATION_METHOD_QR_CODE_SHOW } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt index 1ded9c6c7e32b83f11870cd6cca18470746ec0ee..ddb048a912a87ed70c102faff312838f884915a6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt @@ -30,6 +30,7 @@ import org.matrix.android.sdk.api.session.securestorage.EncryptedSecretContent import org.matrix.android.sdk.api.session.securestorage.IntegrityResult import org.matrix.android.sdk.api.session.securestorage.KeyInfo import org.matrix.android.sdk.api.session.securestorage.KeyInfoResult +import org.matrix.android.sdk.api.session.securestorage.KeyRef import org.matrix.android.sdk.api.session.securestorage.KeySigner import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec import org.matrix.android.sdk.api.session.securestorage.SecretStorageKeyContent @@ -62,10 +63,12 @@ internal class DefaultSharedSecretStorageService @Inject constructor( private val cryptoCoroutineScope: CoroutineScope ) : SharedSecretStorageService { - override suspend fun generateKey(keyId: String, - key: SsssKeySpec?, - keyName: String, - keySigner: KeySigner?): SsssKeyCreationInfo { + override suspend fun generateKey( + keyId: String, + key: SsssKeySpec?, + keyName: String, + keySigner: KeySigner? + ): SsssKeyCreationInfo { return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) { val bytes = (key as? RawBytesKeySpec)?.privateKey ?: ByteArray(32).also { @@ -94,11 +97,13 @@ internal class DefaultSharedSecretStorageService @Inject constructor( } } - override suspend fun generateKeyWithPassphrase(keyId: String, - keyName: String, - passphrase: String, - keySigner: KeySigner, - progressListener: ProgressListener?): SsssKeyCreationInfo { + override suspend fun generateKeyWithPassphrase( + keyId: String, + keyName: String, + passphrase: String, + keySigner: KeySigner, + progressListener: ProgressListener? + ): SsssKeyCreationInfo { return withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) { val privatePart = generatePrivateKeyWithPassword(passphrase, progressListener) @@ -157,7 +162,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor( return getKey(keyId) } - override suspend fun storeSecret(name: String, secretBase64: String, keys: List<SharedSecretStorageService.KeyRef>) { + override suspend fun storeSecret(name: String, secretBase64: String, keys: List<KeyRef>) { withContext(cryptoCoroutineScope.coroutineContext + coroutineDispatchers.computation) { val encryptedContents = HashMap<String, EncryptedSecretContent>() keys.forEach { @@ -174,7 +179,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor( throw SharedSecretStorageError.UnknownAlgorithm(key.keyInfo.content.algorithm ?: "") } } - is KeyInfoResult.Error -> throw key.error + is KeyInfoResult.Error -> throw key.error } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt index 480009dbce0c45c56a29916eba6229df1abbbc68..b18de34329452f229e429a1027dd257939440bf3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt @@ -164,16 +164,14 @@ internal interface IMXCryptoStore { /** * Store the end to end account for the logged-in user. - * - * @param account the account to save */ fun saveOlmAccount() /** * Retrieve a device for a user. * + * @param userId the user's id. * @param deviceId the device id. - * @param userId the user's id. * @return the device */ fun getUserDevice(userId: String, deviceId: String): CryptoDeviceInfo? @@ -189,15 +187,17 @@ internal interface IMXCryptoStore { /** * Store the known devices for a user. * - * @param userId The user's id. + * @param userId The user's id. * @param devices A map from device id to 'MXDevice' object for the device. */ fun storeUserDevices(userId: String, devices: Map<String, CryptoDeviceInfo>?) - fun storeUserCrossSigningKeys(userId: String, - masterKey: CryptoCrossSigningKey?, - selfSigningKey: CryptoCrossSigningKey?, - userSigningKey: CryptoCrossSigningKey?) + fun storeUserCrossSigningKeys( + userId: String, + masterKey: CryptoCrossSigningKey?, + selfSigningKey: CryptoCrossSigningKey?, + userSigningKey: CryptoCrossSigningKey? + ) /** * Retrieve the known devices for a user. @@ -225,7 +225,7 @@ internal interface IMXCryptoStore { /** * Store the crypto algorithm for a room. * - * @param roomId the id of the room. + * @param roomId the id of the room. * @param algorithm the algorithm. */ fun storeRoomAlgorithm(roomId: String, algorithm: String?) @@ -253,7 +253,7 @@ internal interface IMXCryptoStore { /** * Store a session between the logged-in user and another device. * - * @param olmSessionWrapper the end-to-end session. + * @param olmSessionWrapper the end-to-end session. * @param deviceKey the public key of the other device. */ fun storeSession(olmSessionWrapper: OlmSessionWrapper, deviceKey: String) @@ -331,7 +331,7 @@ internal interface IMXCryptoStore { /** * Mark inbound group sessions as backed up on the user homeserver. * - * @param sessions the sessions + * @param olmInboundGroupSessionWrappers the sessions */ fun markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers: List<OlmInboundGroupSessionWrapper2>) @@ -361,7 +361,7 @@ internal interface IMXCryptoStore { /** * Get the tracking status of a specified userId devices. * - * @param userId the user id + * @param userId the user id * @param defaultValue the default value * @return the tracking status */ @@ -380,7 +380,9 @@ internal interface IMXCryptoStore { /** * Look for an existing outgoing room key request, and if none is found, add a new one. * - * @param request the request + * @param requestBody the request + * @param recipients list of recipients + * @param fromIndex start index * @return either the same instance as passed in, or the existing one. */ fun getOrAddOutgoingRoomKeyRequest(requestBody: RoomKeyRequestBody, recipients: Map<String, List<String>>, fromIndex: Int): OutgoingKeyRequest @@ -392,7 +394,8 @@ internal interface IMXCryptoStore { algorithm: String, senderKey: String, fromDevice: String?, - event: Event) + event: Event + ) fun deleteOutgoingRoomKeyRequest(requestId: String) fun deleteOutgoingRoomKeyRequestInState(state: OutgoingRoomKeyRequestState) @@ -479,8 +482,14 @@ internal interface IMXCryptoStore { fun addWithHeldMegolmSession(withHeldContent: RoomKeyWithHeldContent) fun getWithHeldMegolmSession(roomId: String, sessionId: String): RoomKeyWithHeldContent? - fun markedSessionAsShared(roomId: String?, sessionId: String, userId: String, deviceId: String, - deviceIdentityKey: String, chainIndex: Int) + fun markedSessionAsShared( + roomId: String?, + sessionId: String, + userId: String, + deviceId: String, + deviceIdentityKey: String, + chainIndex: Int + ) /** * Query for information on this session sharing history. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt index 533ab70bba3ce0095825a10deae8f83d7df07d06..c56e4d320b82ec41cb6a9fb22f42ba9c9c0aaccd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt @@ -322,10 +322,12 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun storeUserCrossSigningKeys(userId: String, - masterKey: CryptoCrossSigningKey?, - selfSigningKey: CryptoCrossSigningKey?, - userSigningKey: CryptoCrossSigningKey?) { + override fun storeUserCrossSigningKeys( + userId: String, + masterKey: CryptoCrossSigningKey?, + selfSigningKey: CryptoCrossSigningKey?, + userSigningKey: CryptoCrossSigningKey? + ) { doRealmTransaction(realmConfiguration) { realm -> UserEntity.getOrCreate(realm, userId) .let { userEntity -> @@ -1154,9 +1156,11 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun getOrAddOutgoingRoomKeyRequest(requestBody: RoomKeyRequestBody, - recipients: Map<String, List<String>>, - fromIndex: Int): OutgoingKeyRequest { + override fun getOrAddOutgoingRoomKeyRequest( + requestBody: RoomKeyRequestBody, + recipients: Map<String, List<String>>, + fromIndex: Int + ): OutgoingKeyRequest { // Insert the request and return the one passed in parameter lateinit var request: OutgoingKeyRequest doRealmTransaction(realmConfiguration) { realm -> @@ -1220,12 +1224,14 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun updateOutgoingRoomKeyReply(roomId: String, - sessionId: String, - algorithm: String, - senderKey: String, - fromDevice: String?, - event: Event) { + override fun updateOutgoingRoomKeyReply( + roomId: String, + sessionId: String, + algorithm: String, + senderKey: String, + fromDevice: String?, + event: Event + ) { doRealmTransaction(realmConfiguration) { realm -> realm.where<OutgoingKeyRequestEntity>() .equalTo(OutgoingKeyRequestEntityFields.ROOM_ID, roomId) @@ -1266,7 +1272,8 @@ internal class RealmCryptoStore @Inject constructor( senderKey: String, algorithm: String, fromUser: String, - fromDevice: String) { + fromDevice: String + ) { monarchy.writeAsync { realm -> val now = clock.epochMillis() realm.createObject<AuditTrailEntity>().apply { @@ -1288,13 +1295,15 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun saveWithheldAuditTrail(roomId: String, - sessionId: String, - senderKey: String, - algorithm: String, - code: WithHeldCode, - userId: String, - deviceId: String) { + override fun saveWithheldAuditTrail( + roomId: String, + sessionId: String, + senderKey: String, + algorithm: String, + code: WithHeldCode, + userId: String, + deviceId: String + ) { monarchy.writeAsync { realm -> val now = clock.epochMillis() realm.createObject<AuditTrailEntity>().apply { @@ -1316,34 +1325,39 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun saveForwardKeyAuditTrail(roomId: String, - sessionId: String, - senderKey: String, - algorithm: String, - userId: String, - deviceId: String, - chainIndex: Long?) { + override fun saveForwardKeyAuditTrail( + roomId: String, + sessionId: String, + senderKey: String, + algorithm: String, + userId: String, + deviceId: String, + chainIndex: Long? + ) { saveForwardKeyTrail(roomId, sessionId, senderKey, algorithm, userId, deviceId, chainIndex, false) } - override fun saveIncomingForwardKeyAuditTrail(roomId: String, - sessionId: String, - senderKey: String, - algorithm: String, - userId: String, - deviceId: String, - chainIndex: Long?) { + override fun saveIncomingForwardKeyAuditTrail( + roomId: String, + sessionId: String, + senderKey: String, + algorithm: String, + userId: String, + deviceId: String, + chainIndex: Long? + ) { saveForwardKeyTrail(roomId, sessionId, senderKey, algorithm, userId, deviceId, chainIndex, true) } - private fun saveForwardKeyTrail(roomId: String, - sessionId: String, - senderKey: String, - algorithm: String, - userId: String, - deviceId: String, - chainIndex: Long?, - incoming: Boolean + private fun saveForwardKeyTrail( + roomId: String, + sessionId: String, + senderKey: String, + algorithm: String, + userId: String, + deviceId: String, + chainIndex: Long?, + incoming: Boolean ) { monarchy.writeAsync { realm -> val now = clock.epochMillis() @@ -1617,12 +1631,14 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun markedSessionAsShared(roomId: String?, - sessionId: String, - userId: String, - deviceId: String, - deviceIdentityKey: String, - chainIndex: Int) { + override fun markedSessionAsShared( + roomId: String?, + sessionId: String, + userId: String, + deviceId: String, + deviceIdentityKey: String, + chainIndex: Int + ) { doRealmTransaction(realmConfiguration) { realm -> SharedSessionEntity.create( realm = realm, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt index e5bdd2aa9b7c436396832b9d412e1374ca1d7199..0a986892d98a4182ab16d6a15620c3a7f04a08a0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/migration/MigrateCryptoTo004.kt @@ -104,10 +104,10 @@ internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) val trustLevel = realm.createObject("TrustLevelEntity") when (oldDevice.verified) { - MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> { + MXDeviceInfo.DEVICE_VERIFICATION_UNKNOWN -> { obj.setNull(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`) } - MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> { + MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED -> { trustLevel.setNull(TrustLevelEntityFields.LOCALLY_VERIFIED) trustLevel.setNull(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED) obj.setBoolean(DeviceInfoEntityFields.IS_BLOCKED, oldDevice.isBlocked) @@ -118,7 +118,7 @@ internal class MigrateCryptoTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false) obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel) } - MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> { + MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED -> { trustLevel.setBoolean(TrustLevelEntityFields.LOCALLY_VERIFIED, true) trustLevel.setBoolean(TrustLevelEntityFields.CROSS_SIGNED_VERIFIED, false) obj.setObject(DeviceInfoEntityFields.TRUST_LEVEL_ENTITY.`$`, trustLevel) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt index 80ae4a8d0d39ec3c79f8dc99cb51b19b303670d8..fe8e9f1db731c42fb7a4752aed291591319147f0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/AuditTrailMapper.kt @@ -30,7 +30,7 @@ internal object AuditTrailMapper { fun map(entity: AuditTrailEntity): AuditTrail? { val contentJson = entity.contentJson ?: return null return when (entity.type) { - TrailType.OutgoingKeyForward.name -> { + TrailType.OutgoingKeyForward.name -> { val info = tryOrNull { MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).fromJson(contentJson) } ?: return null @@ -50,7 +50,7 @@ internal object AuditTrailMapper { info = info ) } - TrailType.IncomingKeyRequest.name -> { + TrailType.IncomingKeyRequest.name -> { val info = tryOrNull { MoshiProvider.providesMoshi().adapter(IncomingKeyRequestInfo::class.java).fromJson(contentJson) } ?: return null @@ -60,7 +60,7 @@ internal object AuditTrailMapper { info = info ) } - TrailType.IncomingKeyForward.name -> { + TrailType.IncomingKeyForward.name -> { val info = tryOrNull { MoshiProvider.providesMoshi().adapter(ForwardInfo::class.java).fromJson(contentJson) } ?: return null @@ -70,7 +70,7 @@ internal object AuditTrailMapper { info = info ) } - else -> { + else -> { AuditTrail( ageLocalTs = entity.ageLocalTs ?: 0, type = TrailType.Unknown, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt index 83671b28d95e387ba48f2b2b9211a4a47c4d5e7d..a4f6c279acb964fd1697847a0edc7c9f3b545831 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmInboundGroupSessionEntity.kt @@ -33,7 +33,8 @@ internal open class OlmInboundGroupSessionEntity( // olmInboundGroupSessionData contains Json var olmInboundGroupSessionData: String? = null, // Indicate if the key has been backed up to the homeserver - var backedUp: Boolean = false) : + var backedUp: Boolean = false +) : RealmObject() { fun getInboundGroupSession(): OlmInboundGroupSessionWrapper2? { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmSessionEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmSessionEntity.kt index 1a637d76c4ac8c9dc81fd1e924d4ee4196a39e45..9f010db288ea63437130b0eed147bc941d1dbf8f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmSessionEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OlmSessionEntity.kt @@ -25,11 +25,13 @@ import org.matrix.olm.OlmSession internal fun OlmSessionEntity.Companion.createPrimaryKey(sessionId: String, deviceKey: String) = "$sessionId|$deviceKey" // olmSessionData is a serialized OlmSession -internal open class OlmSessionEntity(@PrimaryKey var primaryKey: String = "", - var sessionId: String? = null, - var deviceKey: String? = null, - var olmSessionData: String? = null, - var lastReceivedMessageTs: Long = 0) : +internal open class OlmSessionEntity( + @PrimaryKey var primaryKey: String = "", + var sessionId: String? = null, + var deviceKey: String? = null, + var olmSessionData: String? = null, + var lastReceivedMessageTs: Long = 0 +) : RealmObject() { fun getOlmSession(): OlmSession? { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt index 7a8ba188093879501e5033e7066debdc34f7f6f1..854d148b76c66be956c91c95de583bcacd83f6c9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/OutgoingKeyRequestEntity.kt @@ -117,7 +117,7 @@ internal open class OutgoingKeyRequestEntity( private fun eventToResult(event: Event): RequestResult? { return when (event.getClearType()) { - EventType.ROOM_KEY_WITHHELD -> { + EventType.ROOM_KEY_WITHHELD -> { event.content.toModel<RoomKeyWithHeldContent>()?.code?.let { RequestResult.Failure(it) } @@ -125,7 +125,7 @@ internal open class OutgoingKeyRequestEntity( EventType.FORWARDED_ROOM_KEY -> { RequestResult.Success((event.content?.get("chain_index") as? Number)?.toInt() ?: 0) } - else -> null + else -> null } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/SharedSessionQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/SharedSessionQueries.kt index 8bf9794375fb0be360695b1577daf4432c6d958b..85dd50c88ed35605a9284356b716d13a33354029 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/SharedSessionQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/SharedSessionQueries.kt @@ -24,12 +24,14 @@ import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntity import org.matrix.android.sdk.internal.crypto.store.db.model.SharedSessionEntityFields -internal fun SharedSessionEntity.Companion.get(realm: Realm, - roomId: String?, - sessionId: String, - userId: String, - deviceId: String, - deviceIdentityKey: String?): SharedSessionEntity? { +internal fun SharedSessionEntity.Companion.get( + realm: Realm, + roomId: String?, + sessionId: String, + userId: String, + deviceId: String, + deviceIdentityKey: String? +): SharedSessionEntity? { return realm.where<SharedSessionEntity>() .equalTo(SharedSessionEntityFields.ROOM_ID, roomId) .equalTo(SharedSessionEntityFields.SESSION_ID, sessionId) @@ -48,12 +50,15 @@ internal fun SharedSessionEntity.Companion.get(realm: Realm, roomId: String?, se .findAll() } -internal fun SharedSessionEntity.Companion.create(realm: Realm, roomId: String?, - sessionId: String, - userId: String, - deviceId: String, - deviceIdentityKey: String, - chainIndex: Int): SharedSessionEntity { +internal fun SharedSessionEntity.Companion.create( + realm: Realm, + roomId: String?, + sessionId: String, + userId: String, + deviceId: String, + deviceIdentityKey: String, + chainIndex: Int +): SharedSessionEntity { return realm.createObject<SharedSessionEntity>().apply { this.roomId = roomId this.algorithm = MXCRYPTO_ALGORITHM_MEGOLM diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt index 394c6189681ca919ebc27e78efd6fa6e6e6f2096..a4b4cd0761bca993a558e8c857644f64e4be6a8e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt @@ -31,10 +31,11 @@ import org.matrix.android.sdk.internal.task.Task import javax.inject.Inject internal interface EncryptEventTask : Task<EncryptEventTask.Params, Event> { - data class Params(val roomId: String, - val event: Event, - /**Do not encrypt these keys, keep them as is in encrypted content (e.g. m.relates_to)*/ - val keepKeys: List<String>? = null + data class Params( + val roomId: String, + val event: Event, + /**Do not encrypt these keys, keep them as is in encrypted content (e.g. m.relates_to)*/ + val keepKeys: List<String>? = null ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt index d6a7f3c6a026c44d942911446a38fd2064341e72..56bdc8cae88495ac3ca855c2656e206b873fbd53 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt @@ -32,7 +32,8 @@ internal interface RedactEventTask : Task<RedactEventTask.Params, String> { internal class DefaultRedactEventTask @Inject constructor( private val roomAPI: RoomAPI, - private val globalErrorReceiver: GlobalErrorReceiver) : RedactEventTask { + private val globalErrorReceiver: GlobalErrorReceiver +) : RedactEventTask { override suspend fun execute(params: RedactEventTask.Params): String { val response = executeRequest(globalErrorReceiver) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt index 50efe51bc1bb1502d58f7156f863f6bbb46c56ac..fbd9d245d9c1493b29b5f76d357f0e5e27b69ac3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendEventTask.kt @@ -39,7 +39,8 @@ internal class DefaultSendEventTask @Inject constructor( private val encryptEventTask: EncryptEventTask, private val loadRoomMembersTask: LoadRoomMembersTask, private val roomAPI: RoomAPI, - private val globalErrorReceiver: GlobalErrorReceiver) : SendEventTask { + private val globalErrorReceiver: GlobalErrorReceiver +) : SendEventTask { override suspend fun execute(params: SendEventTask.Params): String { try { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt index 7c52c62d92f218ebb593b577aee2724da54ba319..944f41d488b86eacaf103b823dea68eb4244fc6f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/SendVerificationMessageTask.kt @@ -37,7 +37,8 @@ internal class DefaultSendVerificationMessageTask @Inject constructor( private val encryptEventTask: EncryptEventTask, private val roomAPI: RoomAPI, private val cryptoSessionInfoProvider: CryptoSessionInfoProvider, - private val globalErrorReceiver: GlobalErrorReceiver) : SendVerificationMessageTask { + private val globalErrorReceiver: GlobalErrorReceiver +) : SendVerificationMessageTask { override suspend fun execute(params: SendVerificationMessageTask.Params): String { val event = handleEncryption(params) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt index 4ab7e0e30c7bc589a052ddaeb756ab2becd90d40..04fb6c4858878eb943cbd8b6e3ff8170e2d33e8a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/HkdfSha256.kt @@ -35,7 +35,7 @@ internal object HkdfSha256 { /** * HkdfSha256-Extract(salt, IKM) -> PRK. * - * @param salt optional salt value (a non-secret random value); + * @param salt optional salt value (a non-secret random value); * if not provided, it is set to a string of HashLen (size in octets) zeros. * @param ikm input keying material */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt index a9d5cf1191d2dce87dd12969b4c066d5b5b2cf15..6b3bb1e641472acb8e1399e5ac70a07eb8724df2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt @@ -60,26 +60,26 @@ internal class DefaultIncomingSASDefaultVerificationTransaction( override val uxState: IncomingSasVerificationTransaction.UxState get() { return when (val immutableState = state) { - is VerificationTxState.OnStarted -> IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT + is VerificationTxState.OnStarted -> IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT is VerificationTxState.SendingAccept, is VerificationTxState.Accepted, is VerificationTxState.OnKeyReceived, is VerificationTxState.SendingKey, - is VerificationTxState.KeySent -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT + is VerificationTxState.KeySent -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT is VerificationTxState.ShortCodeReady -> IncomingSasVerificationTransaction.UxState.SHOW_SAS is VerificationTxState.ShortCodeAccepted, is VerificationTxState.SendingMac, is VerificationTxState.MacSent, - is VerificationTxState.Verifying -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION - is VerificationTxState.Verified -> IncomingSasVerificationTransaction.UxState.VERIFIED - is VerificationTxState.Cancelled -> { + is VerificationTxState.Verifying -> IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION + is VerificationTxState.Verified -> IncomingSasVerificationTransaction.UxState.VERIFIED + is VerificationTxState.Cancelled -> { if (immutableState.byMe) { IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME } else { IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER } } - else -> IncomingSasVerificationTransaction.UxState.UNKNOWN + else -> IncomingSasVerificationTransaction.UxState.UNKNOWN } } @@ -232,7 +232,7 @@ internal class DefaultIncomingSASDefaultVerificationTransaction( val sasInfo = "MATRIX_KEY_VERIFICATION_SAS|$otherUserId|$otherDeviceId|$otherKey|$userId|$deviceId|${getSAS().publicKey}|$transactionId" return getSAS().generateShortCode(sasInfo, 6) } - else -> { + else -> { // Protocol has been checked earlier throw IllegalArgumentException() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt index ddb8ed232ba1bdc865cbfa313aa3f80d09e269d8..f1cf1b7547c566b211369a5db361d2481986b4f0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt @@ -57,27 +57,27 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction( override val uxState: OutgoingSasVerificationTransaction.UxState get() { return when (val immutableState = state) { - is VerificationTxState.None -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_START + is VerificationTxState.None -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_START is VerificationTxState.SendingStart, is VerificationTxState.Started, is VerificationTxState.OnAccepted, is VerificationTxState.SendingKey, is VerificationTxState.KeySent, - is VerificationTxState.OnKeyReceived -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT + is VerificationTxState.OnKeyReceived -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT is VerificationTxState.ShortCodeReady -> OutgoingSasVerificationTransaction.UxState.SHOW_SAS is VerificationTxState.ShortCodeAccepted, is VerificationTxState.SendingMac, is VerificationTxState.MacSent, - is VerificationTxState.Verifying -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION - is VerificationTxState.Verified -> OutgoingSasVerificationTransaction.UxState.VERIFIED - is VerificationTxState.Cancelled -> { + is VerificationTxState.Verifying -> OutgoingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION + is VerificationTxState.Verified -> OutgoingSasVerificationTransaction.UxState.VERIFIED + is VerificationTxState.Cancelled -> { if (immutableState.byMe) { OutgoingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER } else { OutgoingSasVerificationTransaction.UxState.CANCELLED_BY_ME } } - else -> OutgoingSasVerificationTransaction.UxState.UNKNOWN + else -> OutgoingSasVerificationTransaction.UxState.UNKNOWN } } @@ -224,7 +224,7 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction( val sasInfo = "MATRIX_KEY_VERIFICATION_SAS|$userId|$deviceId|${getSAS().publicKey}|$otherUserId|$otherDeviceId|$otherKey|$transactionId" return getSAS().generateShortCode(sasInfo, 6) } - else -> { + else -> { // Protocol has been checked earlier throw IllegalArgumentException() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt index 6da674d6e4aa1ca996e7b5a1134ded5e686a1a7a..1a04ee030249fabee11171d0f1607a11091052ba 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt @@ -129,31 +129,31 @@ internal class DefaultVerificationService @Inject constructor( Timber.d("## SAS onToDeviceEvent ${event.getClearType()}") cryptoCoroutineScope.launch(coroutineDispatchers.dmVerif) { when (event.getClearType()) { - EventType.KEY_VERIFICATION_START -> { + EventType.KEY_VERIFICATION_START -> { onStartRequestReceived(event) } - EventType.KEY_VERIFICATION_CANCEL -> { + EventType.KEY_VERIFICATION_CANCEL -> { onCancelReceived(event) } - EventType.KEY_VERIFICATION_ACCEPT -> { + EventType.KEY_VERIFICATION_ACCEPT -> { onAcceptReceived(event) } - EventType.KEY_VERIFICATION_KEY -> { + EventType.KEY_VERIFICATION_KEY -> { onKeyReceived(event) } - EventType.KEY_VERIFICATION_MAC -> { + EventType.KEY_VERIFICATION_MAC -> { onMacReceived(event) } - EventType.KEY_VERIFICATION_READY -> { + EventType.KEY_VERIFICATION_READY -> { onReadyReceived(event) } - EventType.KEY_VERIFICATION_DONE -> { + EventType.KEY_VERIFICATION_DONE -> { onDoneReceived(event) } MessageType.MSGTYPE_VERIFICATION_REQUEST -> { onRequestReceived(event) } - else -> { + else -> { // ignore } } @@ -163,7 +163,7 @@ internal class DefaultVerificationService @Inject constructor( fun onRoomEvent(event: Event) { cryptoCoroutineScope.launch(coroutineDispatchers.dmVerif) { when (event.getClearType()) { - EventType.KEY_VERIFICATION_START -> { + EventType.KEY_VERIFICATION_START -> { onRoomStartRequestReceived(event) } EventType.KEY_VERIFICATION_CANCEL -> { @@ -173,24 +173,24 @@ internal class DefaultVerificationService @Inject constructor( EventType.KEY_VERIFICATION_ACCEPT -> { onRoomAcceptReceived(event) } - EventType.KEY_VERIFICATION_KEY -> { + EventType.KEY_VERIFICATION_KEY -> { onRoomKeyRequestReceived(event) } - EventType.KEY_VERIFICATION_MAC -> { + EventType.KEY_VERIFICATION_MAC -> { onRoomMacReceived(event) } - EventType.KEY_VERIFICATION_READY -> { + EventType.KEY_VERIFICATION_READY -> { onRoomReadyReceived(event) } - EventType.KEY_VERIFICATION_DONE -> { + EventType.KEY_VERIFICATION_DONE -> { onRoomDoneReceived(event) } - EventType.MESSAGE -> { + EventType.MESSAGE -> { if (MessageType.MSGTYPE_VERIFICATION_REQUEST == event.getClearContent().toModel<MessageContent>()?.msgType) { onRoomRequestReceived(event) } } - else -> { + else -> { // ignore } } @@ -472,9 +472,11 @@ internal class DefaultVerificationService @Inject constructor( /** * Return a CancelCode to make the caller cancel the verification. Else return null */ - private suspend fun handleStart(otherUserId: String?, - startReq: ValidVerificationInfoStart, - txConfigure: (DefaultVerificationTransaction) -> Unit): CancelCode? { + private suspend fun handleStart( + otherUserId: String?, + startReq: ValidVerificationInfoStart, + txConfigure: (DefaultVerificationTransaction) -> Unit + ): CancelCode? { Timber.d("## SAS onStartRequestReceived $startReq") if (otherUserId?.let { checkKeysAreDownloaded(it, startReq.fromDevice) } != null) { val tid = startReq.transactionId @@ -505,9 +507,9 @@ internal class DefaultVerificationService @Inject constructor( } when (startReq) { - is ValidVerificationInfoStart.SasVerificationInfoStart -> { + is ValidVerificationInfoStart.SasVerificationInfoStart -> { when (existing) { - is SasVerificationTransaction -> { + is SasVerificationTransaction -> { // should cancel both! Timber.v("## SAS onStartRequestReceived - Request exist with same id ${startReq.transactionId}") existing.cancel(CancelCode.UnexpectedMessage) @@ -517,7 +519,7 @@ internal class DefaultVerificationService @Inject constructor( is QrCodeVerificationTransaction -> { // Nothing to do? } - null -> { + null -> { getExistingTransactionsForUser(otherUserId) ?.filterIsInstance(SasVerificationTransaction::class.java) ?.takeIf { it.isNotEmpty() } @@ -589,8 +591,10 @@ internal class DefaultVerificationService @Inject constructor( } // TODO Refacto: It could just return a boolean - private suspend fun checkKeysAreDownloaded(otherUserId: String, - otherDeviceId: String): MXUsersDevicesMap<CryptoDeviceInfo>? { + private suspend fun checkKeysAreDownloaded( + otherUserId: String, + otherDeviceId: String + ): MXUsersDevicesMap<CryptoDeviceInfo>? { return try { var keys = deviceListManager.downloadKeys(listOf(otherUserId), false) if (keys.getUserDeviceIds(otherUserId)?.contains(otherDeviceId) == true) { @@ -899,9 +903,11 @@ internal class DefaultVerificationService @Inject constructor( } } - private fun handleReadyReceived(senderId: String, - readyReq: ValidVerificationInfoReady, - transportCreator: (DefaultVerificationTransaction) -> VerificationTransport) { + private fun handleReadyReceived( + senderId: String, + readyReq: ValidVerificationInfoReady, + transportCreator: (DefaultVerificationTransaction) -> VerificationTransport + ) { val existingRequest = getExistingVerificationRequests(senderId).find { it.transactionId == readyReq.transactionId } if (existingRequest == null) { Timber.e("## SAS Received Ready for unknown request txId:${readyReq.transactionId} fromDevice ${readyReq.fromDevice}") @@ -942,6 +948,22 @@ internal class DefaultVerificationService @Inject constructor( readyInfo = readyReq ) ) + + notifyOthersOfAcceptance(readyReq.transactionId, readyReq.fromDevice) + } + + /** + * Gets a list of device ids excluding the current one. + */ + private fun getMyOtherDeviceIds(): List<String> = cryptoStore.getUserDevices(userId)?.keys?.filter { it != deviceId }.orEmpty() + + /** + * Notifies other devices that the current verification transaction is being handled by [acceptedByDeviceId]. + */ + private fun notifyOthersOfAcceptance(transactionId: String, acceptedByDeviceId: String) { + val deviceIds = getMyOtherDeviceIds().filter { it != acceptedByDeviceId } + val transport = verificationTransportToDeviceFactory.createTransport(null) + transport.cancelTransaction(transactionId, userId, deviceIds, CancelCode.AcceptedByAnotherDevice) } private fun createQrCodeData(requestId: String?, otherUserId: String, otherDeviceId: String?): QrCodeData? { @@ -951,12 +973,12 @@ internal class DefaultVerificationService @Inject constructor( } return when { - userId != otherUserId -> + userId != otherUserId -> createQrCodeDataForDistinctUser(requestId, otherUserId) crossSigningService.isCrossSigningVerified() -> // This is a self verification and I am the old device (Osborne2) createQrCodeDataForVerifiedDevice(requestId, otherDeviceId) - else -> + else -> // This is a self verification and I am the new device (Dynabook) createQrCodeDataForUnVerifiedDevice(requestId) } @@ -1142,10 +1164,12 @@ internal class DefaultVerificationService @Inject constructor( } } - override fun requestKeyVerificationInDMs(methods: List<VerificationMethod>, - otherUserId: String, - roomId: String, - localId: String?): PendingVerificationRequest { + override fun requestKeyVerificationInDMs( + methods: List<VerificationMethod>, + otherUserId: String, + roomId: String, + localId: String? + ): PendingVerificationRequest { Timber.i("## SAS Requesting verification to user: $otherUserId in room $roomId") val requestsForUser = pendingRequests.getOrPut(otherUserId) { mutableListOf() } @@ -1312,11 +1336,13 @@ internal class DefaultVerificationService @Inject constructor( dispatchRequestUpdated(updated) } - override fun beginKeyVerificationInDMs(method: VerificationMethod, - transactionId: String, - roomId: String, - otherUserId: String, - otherDeviceId: String): String { + override fun beginKeyVerificationInDMs( + method: VerificationMethod, + transactionId: String, + roomId: String, + otherUserId: String, + otherDeviceId: String + ): String { if (method == VerificationMethod.SAS) { val tx = DefaultOutgoingSASDefaultVerificationTransaction( setDeviceVerificationAction, @@ -1341,10 +1367,12 @@ internal class DefaultVerificationService @Inject constructor( } } - override fun readyPendingVerificationInDMs(methods: List<VerificationMethod>, - otherUserId: String, - roomId: String, - transactionId: String): Boolean { + override fun readyPendingVerificationInDMs( + methods: List<VerificationMethod>, + otherUserId: String, + roomId: String, + transactionId: String + ): Boolean { Timber.v("## SAS readyPendingVerificationInDMs $otherUserId room:$roomId tx:$transactionId") // Let's find the related request val existingRequest = getExistingVerificationRequest(otherUserId, transactionId) @@ -1383,9 +1411,11 @@ internal class DefaultVerificationService @Inject constructor( } } - override fun readyPendingVerification(methods: List<VerificationMethod>, - otherUserId: String, - transactionId: String): Boolean { + override fun readyPendingVerification( + methods: List<VerificationMethod>, + otherUserId: String, + transactionId: String + ): Boolean { Timber.v("## SAS readyPendingVerification $otherUserId tx:$transactionId") // Let's find the related request val existingRequest = getExistingVerificationRequest(otherUserId, transactionId) @@ -1429,7 +1459,8 @@ internal class DefaultVerificationService @Inject constructor( otherDeviceId: String, otherUserMethods: List<String>?, methods: List<VerificationMethod>, - transportCreator: (DefaultVerificationTransaction) -> VerificationTransport): List<String> { + transportCreator: (DefaultVerificationTransaction) -> VerificationTransport + ): List<String> { if (otherUserMethods.isNullOrEmpty()) { return emptyList() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationTransaction.kt index 27bc7643957340efc11441530427c8c9f4c3c3d8..9d19fd137e028c7b1c21c382effdcab1477ace1f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationTransaction.kt @@ -37,7 +37,8 @@ internal abstract class DefaultVerificationTransaction( override val transactionId: String, override val otherUserId: String, override var otherDeviceId: String? = null, - override val isIncoming: Boolean) : VerificationTransaction { + override val isIncoming: Boolean +) : VerificationTransaction { lateinit var transport: VerificationTransport @@ -55,9 +56,12 @@ internal abstract class DefaultVerificationTransaction( listeners.remove(listener) } - protected fun trust(canTrustOtherUserMasterKey: Boolean, - toVerifyDeviceIds: List<String>, - eventuallyMarkMyMasterKeyAsTrusted: Boolean, autoDone: Boolean = true) { + protected fun trust( + canTrustOtherUserMasterKey: Boolean, + toVerifyDeviceIds: List<String>, + eventuallyMarkMyMasterKeyAsTrusted: Boolean, + autoDone: Boolean = true + ) { Timber.d("## Verification: trust ($otherUserId,$otherDeviceId) , verifiedDevices:$toVerifyDeviceIds") Timber.d("## Verification: trust Mark myMSK trusted $eventuallyMarkMyMasterKeyAsTrusted") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt index 68dd57478e62af81575a51f90ea3c1c7d6253343..1cbaff059aed85ba43437f2f9f386a157cc79da4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt @@ -314,11 +314,13 @@ internal abstract class SASDefaultVerificationTransaction( transport.cancelTransaction(transactionId, otherUserId, otherDeviceId ?: "", code) } - protected fun <T> sendToOther(type: String, - keyToDevice: VerificationInfo<T>, - nextState: VerificationTxState, - onErrorReason: CancelCode, - onDone: (() -> Unit)?) { + protected fun <T> sendToOther( + type: String, + keyToDevice: VerificationInfo<T>, + nextState: VerificationTxState, + onErrorReason: CancelCode, + onDone: (() -> Unit)? + ) { transport.sendToOther(type, keyToDevice, nextState, onErrorReason, onDone) } @@ -331,11 +333,11 @@ internal abstract class SASDefaultVerificationTransaction( if (shortCodeBytes!!.size < 5) return null return getDecimalCodeRepresentation(shortCodeBytes!!) } - SasMode.EMOJI -> { + SasMode.EMOJI -> { if (shortCodeBytes!!.size < 6) return null return getEmojiCodeRepresentation(shortCodeBytes!!).joinToString(" ") { it.emoji } } - else -> return null + else -> return null } } @@ -360,8 +362,8 @@ internal abstract class SASDefaultVerificationTransaction( private fun macUsingAgreedMethod(message: String, info: String): String? { return when (accepted?.messageAuthenticationCode?.lowercase(Locale.ROOT)) { SAS_MAC_SHA256_LONGKDF -> getSAS().calculateMacLongKdf(message, info) - SAS_MAC_SHA256 -> getSAS().calculateMac(message, info) - else -> null + SAS_MAC_SHA256 -> getSAS().calculateMac(message, info) + else -> null } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt index eb1819fe6a95318030847e0ce19f5923897a7fb7..cff3591771b02c986e48e978b660f5e123f698fa 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt @@ -20,69 +20,69 @@ import org.matrix.android.sdk.api.session.crypto.verification.EmojiRepresentatio internal fun getEmojiForCode(code: Int): EmojiRepresentation { return when (code % 64) { - 0 -> EmojiRepresentation("ðŸ¶", R.string.verification_emoji_dog, R.drawable.ic_verification_dog) - 1 -> EmojiRepresentation("ðŸ±", R.string.verification_emoji_cat, R.drawable.ic_verification_cat) - 2 -> EmojiRepresentation("ðŸ¦", R.string.verification_emoji_lion, R.drawable.ic_verification_lion) - 3 -> EmojiRepresentation("ðŸŽ", R.string.verification_emoji_horse, R.drawable.ic_verification_horse) - 4 -> EmojiRepresentation("🦄", R.string.verification_emoji_unicorn, R.drawable.ic_verification_unicorn) - 5 -> EmojiRepresentation("ðŸ·", R.string.verification_emoji_pig, R.drawable.ic_verification_pig) - 6 -> EmojiRepresentation("ðŸ˜", R.string.verification_emoji_elephant, R.drawable.ic_verification_elephant) - 7 -> EmojiRepresentation("ðŸ°", R.string.verification_emoji_rabbit, R.drawable.ic_verification_rabbit) - 8 -> EmojiRepresentation("ðŸ¼", R.string.verification_emoji_panda, R.drawable.ic_verification_panda) - 9 -> EmojiRepresentation("ðŸ“", R.string.verification_emoji_rooster, R.drawable.ic_verification_rooster) - 10 -> EmojiRepresentation("ðŸ§", R.string.verification_emoji_penguin, R.drawable.ic_verification_penguin) - 11 -> EmojiRepresentation("ðŸ¢", R.string.verification_emoji_turtle, R.drawable.ic_verification_turtle) - 12 -> EmojiRepresentation("ðŸŸ", R.string.verification_emoji_fish, R.drawable.ic_verification_fish) - 13 -> EmojiRepresentation("ðŸ™", R.string.verification_emoji_octopus, R.drawable.ic_verification_octopus) - 14 -> EmojiRepresentation("🦋", R.string.verification_emoji_butterfly, R.drawable.ic_verification_butterfly) - 15 -> EmojiRepresentation("🌷", R.string.verification_emoji_flower, R.drawable.ic_verification_flower) - 16 -> EmojiRepresentation("🌳", R.string.verification_emoji_tree, R.drawable.ic_verification_tree) - 17 -> EmojiRepresentation("🌵", R.string.verification_emoji_cactus, R.drawable.ic_verification_cactus) - 18 -> EmojiRepresentation("ðŸ„", R.string.verification_emoji_mushroom, R.drawable.ic_verification_mushroom) - 19 -> EmojiRepresentation("ðŸŒ", R.string.verification_emoji_globe, R.drawable.ic_verification_globe) - 20 -> EmojiRepresentation("🌙", R.string.verification_emoji_moon, R.drawable.ic_verification_moon) - 21 -> EmojiRepresentation("â˜ï¸", R.string.verification_emoji_cloud, R.drawable.ic_verification_cloud) - 22 -> EmojiRepresentation("🔥", R.string.verification_emoji_fire, R.drawable.ic_verification_fire) - 23 -> EmojiRepresentation("ðŸŒ", R.string.verification_emoji_banana, R.drawable.ic_verification_banana) - 24 -> EmojiRepresentation("ðŸŽ", R.string.verification_emoji_apple, R.drawable.ic_verification_apple) - 25 -> EmojiRepresentation("ðŸ“", R.string.verification_emoji_strawberry, R.drawable.ic_verification_strawberry) - 26 -> EmojiRepresentation("🌽", R.string.verification_emoji_corn, R.drawable.ic_verification_corn) - 27 -> EmojiRepresentation("ðŸ•", R.string.verification_emoji_pizza, R.drawable.ic_verification_pizza) - 28 -> EmojiRepresentation("🎂", R.string.verification_emoji_cake, R.drawable.ic_verification_cake) - 29 -> EmojiRepresentation("â¤ï¸", R.string.verification_emoji_heart, R.drawable.ic_verification_heart) - 30 -> EmojiRepresentation("🙂", R.string.verification_emoji_smiley, R.drawable.ic_verification_smiley) - 31 -> EmojiRepresentation("🤖", R.string.verification_emoji_robot, R.drawable.ic_verification_robot) - 32 -> EmojiRepresentation("🎩", R.string.verification_emoji_hat, R.drawable.ic_verification_hat) - 33 -> EmojiRepresentation("👓", R.string.verification_emoji_glasses, R.drawable.ic_verification_glasses) - 34 -> EmojiRepresentation("🔧", R.string.verification_emoji_spanner, R.drawable.ic_verification_spanner) - 35 -> EmojiRepresentation("🎅", R.string.verification_emoji_santa, R.drawable.ic_verification_santa) - 36 -> EmojiRepresentation("ðŸ‘", R.string.verification_emoji_thumbs_up, R.drawable.ic_verification_thumbs_up) - 37 -> EmojiRepresentation("☂ï¸", R.string.verification_emoji_umbrella, R.drawable.ic_verification_umbrella) - 38 -> EmojiRepresentation("⌛", R.string.verification_emoji_hourglass, R.drawable.ic_verification_hourglass) - 39 -> EmojiRepresentation("â°", R.string.verification_emoji_clock, R.drawable.ic_verification_clock) - 40 -> EmojiRepresentation("ðŸŽ", R.string.verification_emoji_gift, R.drawable.ic_verification_gift) - 41 -> EmojiRepresentation("💡", R.string.verification_emoji_light_bulb, R.drawable.ic_verification_light_bulb) - 42 -> EmojiRepresentation("📕", R.string.verification_emoji_book, R.drawable.ic_verification_book) - 43 -> EmojiRepresentation("âœï¸", R.string.verification_emoji_pencil, R.drawable.ic_verification_pencil) - 44 -> EmojiRepresentation("📎", R.string.verification_emoji_paperclip, R.drawable.ic_verification_paperclip) - 45 -> EmojiRepresentation("✂ï¸", R.string.verification_emoji_scissors, R.drawable.ic_verification_scissors) - 46 -> EmojiRepresentation("🔒", R.string.verification_emoji_lock, R.drawable.ic_verification_lock) - 47 -> EmojiRepresentation("🔑", R.string.verification_emoji_key, R.drawable.ic_verification_key) - 48 -> EmojiRepresentation("🔨", R.string.verification_emoji_hammer, R.drawable.ic_verification_hammer) - 49 -> EmojiRepresentation("☎ï¸", R.string.verification_emoji_telephone, R.drawable.ic_verification_phone) - 50 -> EmojiRepresentation("ðŸ", R.string.verification_emoji_flag, R.drawable.ic_verification_flag) - 51 -> EmojiRepresentation("🚂", R.string.verification_emoji_train, R.drawable.ic_verification_train) - 52 -> EmojiRepresentation("🚲", R.string.verification_emoji_bicycle, R.drawable.ic_verification_bicycle) - 53 -> EmojiRepresentation("✈ï¸", R.string.verification_emoji_aeroplane, R.drawable.ic_verification_aeroplane) - 54 -> EmojiRepresentation("🚀", R.string.verification_emoji_rocket, R.drawable.ic_verification_rocket) - 55 -> EmojiRepresentation("ðŸ†", R.string.verification_emoji_trophy, R.drawable.ic_verification_trophy) - 56 -> EmojiRepresentation("âš½", R.string.verification_emoji_ball, R.drawable.ic_verification_ball) - 57 -> EmojiRepresentation("🎸", R.string.verification_emoji_guitar, R.drawable.ic_verification_guitar) - 58 -> EmojiRepresentation("🎺", R.string.verification_emoji_trumpet, R.drawable.ic_verification_trumpet) - 59 -> EmojiRepresentation("🔔", R.string.verification_emoji_bell, R.drawable.ic_verification_bell) - 60 -> EmojiRepresentation("âš“", R.string.verification_emoji_anchor, R.drawable.ic_verification_anchor) - 61 -> EmojiRepresentation("🎧", R.string.verification_emoji_headphones, R.drawable.ic_verification_headphones) - 62 -> EmojiRepresentation("ðŸ“", R.string.verification_emoji_folder, R.drawable.ic_verification_folder) + 0 -> EmojiRepresentation("ðŸ¶", R.string.verification_emoji_dog, R.drawable.ic_verification_dog) + 1 -> EmojiRepresentation("ðŸ±", R.string.verification_emoji_cat, R.drawable.ic_verification_cat) + 2 -> EmojiRepresentation("ðŸ¦", R.string.verification_emoji_lion, R.drawable.ic_verification_lion) + 3 -> EmojiRepresentation("ðŸŽ", R.string.verification_emoji_horse, R.drawable.ic_verification_horse) + 4 -> EmojiRepresentation("🦄", R.string.verification_emoji_unicorn, R.drawable.ic_verification_unicorn) + 5 -> EmojiRepresentation("ðŸ·", R.string.verification_emoji_pig, R.drawable.ic_verification_pig) + 6 -> EmojiRepresentation("ðŸ˜", R.string.verification_emoji_elephant, R.drawable.ic_verification_elephant) + 7 -> EmojiRepresentation("ðŸ°", R.string.verification_emoji_rabbit, R.drawable.ic_verification_rabbit) + 8 -> EmojiRepresentation("ðŸ¼", R.string.verification_emoji_panda, R.drawable.ic_verification_panda) + 9 -> EmojiRepresentation("ðŸ“", R.string.verification_emoji_rooster, R.drawable.ic_verification_rooster) + 10 -> EmojiRepresentation("ðŸ§", R.string.verification_emoji_penguin, R.drawable.ic_verification_penguin) + 11 -> EmojiRepresentation("ðŸ¢", R.string.verification_emoji_turtle, R.drawable.ic_verification_turtle) + 12 -> EmojiRepresentation("ðŸŸ", R.string.verification_emoji_fish, R.drawable.ic_verification_fish) + 13 -> EmojiRepresentation("ðŸ™", R.string.verification_emoji_octopus, R.drawable.ic_verification_octopus) + 14 -> EmojiRepresentation("🦋", R.string.verification_emoji_butterfly, R.drawable.ic_verification_butterfly) + 15 -> EmojiRepresentation("🌷", R.string.verification_emoji_flower, R.drawable.ic_verification_flower) + 16 -> EmojiRepresentation("🌳", R.string.verification_emoji_tree, R.drawable.ic_verification_tree) + 17 -> EmojiRepresentation("🌵", R.string.verification_emoji_cactus, R.drawable.ic_verification_cactus) + 18 -> EmojiRepresentation("ðŸ„", R.string.verification_emoji_mushroom, R.drawable.ic_verification_mushroom) + 19 -> EmojiRepresentation("ðŸŒ", R.string.verification_emoji_globe, R.drawable.ic_verification_globe) + 20 -> EmojiRepresentation("🌙", R.string.verification_emoji_moon, R.drawable.ic_verification_moon) + 21 -> EmojiRepresentation("â˜ï¸", R.string.verification_emoji_cloud, R.drawable.ic_verification_cloud) + 22 -> EmojiRepresentation("🔥", R.string.verification_emoji_fire, R.drawable.ic_verification_fire) + 23 -> EmojiRepresentation("ðŸŒ", R.string.verification_emoji_banana, R.drawable.ic_verification_banana) + 24 -> EmojiRepresentation("ðŸŽ", R.string.verification_emoji_apple, R.drawable.ic_verification_apple) + 25 -> EmojiRepresentation("ðŸ“", R.string.verification_emoji_strawberry, R.drawable.ic_verification_strawberry) + 26 -> EmojiRepresentation("🌽", R.string.verification_emoji_corn, R.drawable.ic_verification_corn) + 27 -> EmojiRepresentation("ðŸ•", R.string.verification_emoji_pizza, R.drawable.ic_verification_pizza) + 28 -> EmojiRepresentation("🎂", R.string.verification_emoji_cake, R.drawable.ic_verification_cake) + 29 -> EmojiRepresentation("â¤ï¸", R.string.verification_emoji_heart, R.drawable.ic_verification_heart) + 30 -> EmojiRepresentation("🙂", R.string.verification_emoji_smiley, R.drawable.ic_verification_smiley) + 31 -> EmojiRepresentation("🤖", R.string.verification_emoji_robot, R.drawable.ic_verification_robot) + 32 -> EmojiRepresentation("🎩", R.string.verification_emoji_hat, R.drawable.ic_verification_hat) + 33 -> EmojiRepresentation("👓", R.string.verification_emoji_glasses, R.drawable.ic_verification_glasses) + 34 -> EmojiRepresentation("🔧", R.string.verification_emoji_spanner, R.drawable.ic_verification_spanner) + 35 -> EmojiRepresentation("🎅", R.string.verification_emoji_santa, R.drawable.ic_verification_santa) + 36 -> EmojiRepresentation("ðŸ‘", R.string.verification_emoji_thumbs_up, R.drawable.ic_verification_thumbs_up) + 37 -> EmojiRepresentation("☂ï¸", R.string.verification_emoji_umbrella, R.drawable.ic_verification_umbrella) + 38 -> EmojiRepresentation("⌛", R.string.verification_emoji_hourglass, R.drawable.ic_verification_hourglass) + 39 -> EmojiRepresentation("â°", R.string.verification_emoji_clock, R.drawable.ic_verification_clock) + 40 -> EmojiRepresentation("ðŸŽ", R.string.verification_emoji_gift, R.drawable.ic_verification_gift) + 41 -> EmojiRepresentation("💡", R.string.verification_emoji_light_bulb, R.drawable.ic_verification_light_bulb) + 42 -> EmojiRepresentation("📕", R.string.verification_emoji_book, R.drawable.ic_verification_book) + 43 -> EmojiRepresentation("âœï¸", R.string.verification_emoji_pencil, R.drawable.ic_verification_pencil) + 44 -> EmojiRepresentation("📎", R.string.verification_emoji_paperclip, R.drawable.ic_verification_paperclip) + 45 -> EmojiRepresentation("✂ï¸", R.string.verification_emoji_scissors, R.drawable.ic_verification_scissors) + 46 -> EmojiRepresentation("🔒", R.string.verification_emoji_lock, R.drawable.ic_verification_lock) + 47 -> EmojiRepresentation("🔑", R.string.verification_emoji_key, R.drawable.ic_verification_key) + 48 -> EmojiRepresentation("🔨", R.string.verification_emoji_hammer, R.drawable.ic_verification_hammer) + 49 -> EmojiRepresentation("☎ï¸", R.string.verification_emoji_telephone, R.drawable.ic_verification_phone) + 50 -> EmojiRepresentation("ðŸ", R.string.verification_emoji_flag, R.drawable.ic_verification_flag) + 51 -> EmojiRepresentation("🚂", R.string.verification_emoji_train, R.drawable.ic_verification_train) + 52 -> EmojiRepresentation("🚲", R.string.verification_emoji_bicycle, R.drawable.ic_verification_bicycle) + 53 -> EmojiRepresentation("✈ï¸", R.string.verification_emoji_aeroplane, R.drawable.ic_verification_aeroplane) + 54 -> EmojiRepresentation("🚀", R.string.verification_emoji_rocket, R.drawable.ic_verification_rocket) + 55 -> EmojiRepresentation("ðŸ†", R.string.verification_emoji_trophy, R.drawable.ic_verification_trophy) + 56 -> EmojiRepresentation("âš½", R.string.verification_emoji_ball, R.drawable.ic_verification_ball) + 57 -> EmojiRepresentation("🎸", R.string.verification_emoji_guitar, R.drawable.ic_verification_guitar) + 58 -> EmojiRepresentation("🎺", R.string.verification_emoji_trumpet, R.drawable.ic_verification_trumpet) + 59 -> EmojiRepresentation("🔔", R.string.verification_emoji_bell, R.drawable.ic_verification_bell) + 60 -> EmojiRepresentation("âš“", R.string.verification_emoji_anchor, R.drawable.ic_verification_anchor) + 61 -> EmojiRepresentation("🎧", R.string.verification_emoji_headphones, R.drawable.ic_verification_headphones) + 62 -> EmojiRepresentation("ðŸ“", R.string.verification_emoji_folder, R.drawable.ic_verification_folder) /* 63 */ else -> EmojiRepresentation("📌", R.string.verification_emoji_pin, R.drawable.ic_verification_pin) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoAccept.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoAccept.kt index 3ddb0ca758038f50c9520931c3890b69327702b2..0b9287cb052e23a1c388853e5098425665e8bd79 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoAccept.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoAccept.kt @@ -63,12 +63,14 @@ internal interface VerificationInfoAccept : VerificationInfo<ValidVerificationIn internal interface VerificationInfoAcceptFactory { - fun create(tid: String, - keyAgreementProtocol: String, - hash: String, - commitment: String, - messageAuthenticationCode: String, - shortAuthenticationStrings: List<String>): VerificationInfoAccept + fun create( + tid: String, + keyAgreementProtocol: String, + hash: String, + commitment: String, + messageAuthenticationCode: String, + shortAuthenticationStrings: List<String> + ): VerificationInfoAccept } internal data class ValidVerificationInfoAccept( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoStart.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoStart.kt index d71bd7359ee8a5cc932f58d20a5ec0faff38e67a..66591fe00f05c6b0cf639d844624d56e1ea0eff6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoStart.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationInfoStart.kt @@ -68,7 +68,7 @@ internal interface VerificationInfoStart : VerificationInfo<ValidVerificationInf val validFromDevice = fromDevice?.takeIf { it.isNotEmpty() } ?: return null return when (method) { - VERIFICATION_METHOD_SAS -> { + VERIFICATION_METHOD_SAS -> { val validKeyAgreementProtocols = keyAgreementProtocols?.takeIf { it.isNotEmpty() } ?: return null val validHashes = hashes?.takeIf { it.contains("sha256") } ?: return null val validMessageAuthenticationCodes = messageAuthenticationCodes @@ -98,14 +98,15 @@ internal interface VerificationInfoStart : VerificationInfo<ValidVerificationInf validSharedSecret ) } - else -> null + else -> null } } } internal sealed class ValidVerificationInfoStart( open val transactionId: String, - open val fromDevice: String) { + open val fromDevice: String +) { data class SasVerificationInfoStart( override val transactionId: String, override val fromDevice: String, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationMessageProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationMessageProcessor.kt index 303b6c5839ffbe23dbbd3edfd98490ed7953eee1..9f123f0c08638163b26a6c3288793c29656fb693 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationMessageProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationMessageProcessor.kt @@ -131,7 +131,7 @@ internal class VerificationMessageProcessor @Inject constructor( EventType.KEY_VERIFICATION_DONE -> { verificationService.onRoomEvent(event) } - EventType.MESSAGE -> { + EventType.MESSAGE -> { if (MessageType.MSGTYPE_VERIFICATION_REQUEST == event.getClearContent().toModel<MessageContent>()?.msgType) { verificationService.onRoomRequestReceived(event) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransport.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransport.kt index c12aea9d52df4c51baab15eceddcc829cb35ea1d..5314c238707e249787fd8907e055205b60c904cb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransport.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransport.kt @@ -28,69 +28,101 @@ internal interface VerificationTransport { /** * Sends a message. */ - fun <T> sendToOther(type: String, - verificationInfo: VerificationInfo<T>, - nextState: VerificationTxState, - onErrorReason: CancelCode, - onDone: (() -> Unit)?) + fun <T> sendToOther( + type: String, + verificationInfo: VerificationInfo<T>, + nextState: VerificationTxState, + onErrorReason: CancelCode, + onDone: (() -> Unit)? + ) /** + * @param supportedMethods list of supported method by this client + * @param localId a local Id + * @param otherUserId the user id to send the verification request to + * @param roomId a room Id to use to send verification message + * @param toDevices list of device Ids * @param callback will be called with eventId and ValidVerificationInfoRequest in case of success */ - fun sendVerificationRequest(supportedMethods: List<String>, - localId: String, - otherUserId: String, - roomId: String?, - toDevices: List<String>?, - callback: (String?, ValidVerificationInfoRequest?) -> Unit) + fun sendVerificationRequest( + supportedMethods: List<String>, + localId: String, + otherUserId: String, + roomId: String?, + toDevices: List<String>?, + callback: (String?, ValidVerificationInfoRequest?) -> Unit + ) - fun cancelTransaction(transactionId: String, - otherUserId: String, - otherUserDeviceId: String?, - code: CancelCode) + fun cancelTransaction( + transactionId: String, + otherUserId: String, + otherUserDeviceId: String?, + code: CancelCode + ) - fun done(transactionId: String, - onDone: (() -> Unit)?) + fun cancelTransaction( + transactionId: String, + otherUserId: String, + otherUserDeviceIds: List<String>, + code: CancelCode + ) + + fun done( + transactionId: String, + onDone: (() -> Unit)? + ) /** * Creates an accept message suitable for this transport. */ - fun createAccept(tid: String, - keyAgreementProtocol: String, - hash: String, - commitment: String, - messageAuthenticationCode: String, - shortAuthenticationStrings: List<String>): VerificationInfoAccept + fun createAccept( + tid: String, + keyAgreementProtocol: String, + hash: String, + commitment: String, + messageAuthenticationCode: String, + shortAuthenticationStrings: List<String> + ): VerificationInfoAccept - fun createKey(tid: String, - pubKey: String): VerificationInfoKey + fun createKey( + tid: String, + pubKey: String + ): VerificationInfoKey /** * Create start for SAS verification. */ - fun createStartForSas(fromDevice: String, - transactionId: String, - keyAgreementProtocols: List<String>, - hashes: List<String>, - messageAuthenticationCodes: List<String>, - shortAuthenticationStrings: List<String>): VerificationInfoStart + fun createStartForSas( + fromDevice: String, + transactionId: String, + keyAgreementProtocols: List<String>, + hashes: List<String>, + messageAuthenticationCodes: List<String>, + shortAuthenticationStrings: List<String> + ): VerificationInfoStart /** * Create start for QR code verification. */ - fun createStartForQrCode(fromDevice: String, - transactionId: String, - sharedSecret: String): VerificationInfoStart + fun createStartForQrCode( + fromDevice: String, + transactionId: String, + sharedSecret: String + ): VerificationInfoStart fun createMac(tid: String, mac: Map<String, String>, keys: String): VerificationInfoMac - fun createReady(tid: String, - fromDevice: String, - methods: List<String>): VerificationInfoReady + fun createReady( + tid: String, + fromDevice: String, + methods: List<String> + ): VerificationInfoReady // TODO Refactor - fun sendVerificationReady(keyReq: VerificationInfoReady, - otherUserId: String, - otherDeviceId: String?, - callback: (() -> Unit)?) + fun sendVerificationReady( + keyReq: VerificationInfoReady, + otherUserId: String, + otherDeviceId: String?, + callback: (() -> Unit)? + ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportRoomMessage.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportRoomMessage.kt index e32828af23850154040aa9db82f8e738153de544..f38a604890bc413d0168ed81fcf8e473c78b785d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportRoomMessage.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportRoomMessage.kt @@ -61,11 +61,13 @@ internal class VerificationTransportRoomMessage( private val verificationSenderScope = CoroutineScope(cryptoCoroutineScope.coroutineContext + dispatcher) private val sequencer = SemaphoreCoroutineSequencer() - override fun <T> sendToOther(type: String, - verificationInfo: VerificationInfo<T>, - nextState: VerificationTxState, - onErrorReason: CancelCode, - onDone: (() -> Unit)?) { + override fun <T> sendToOther( + type: String, + verificationInfo: VerificationInfo<T>, + nextState: VerificationTxState, + onErrorReason: CancelCode, + onDone: (() -> Unit)? + ) { Timber.d("## SAS sending msg type $type") Timber.v("## SAS sending msg info $verificationInfo") val event = createEventAndLocalEcho( @@ -92,12 +94,14 @@ internal class VerificationTransportRoomMessage( } } - override fun sendVerificationRequest(supportedMethods: List<String>, - localId: String, - otherUserId: String, - roomId: String?, - toDevices: List<String>?, - callback: (String?, ValidVerificationInfoRequest?) -> Unit) { + override fun sendVerificationRequest( + supportedMethods: List<String>, + localId: String, + otherUserId: String, + roomId: String?, + toDevices: List<String>?, + callback: (String?, ValidVerificationInfoRequest?) -> Unit + ) { Timber.d("## SAS sending verification request with supported methods: $supportedMethods") // This transport requires a room requireNotNull(roomId) @@ -160,8 +164,17 @@ internal class VerificationTransportRoomMessage( } } - override fun done(transactionId: String, - onDone: (() -> Unit)?) { + override fun cancelTransaction( + transactionId: String, + otherUserId: String, + otherUserDeviceIds: List<String>, + code: CancelCode + ) = cancelTransaction(transactionId, otherUserId, null, code) + + override fun done( + transactionId: String, + onDone: (() -> Unit)? + ) { Timber.d("## SAS sending done for $transactionId") val event = createEventAndLocalEcho( type = EventType.KEY_VERIFICATION_DONE, @@ -188,12 +201,14 @@ internal class VerificationTransportRoomMessage( } } - override fun createAccept(tid: String, - keyAgreementProtocol: String, - hash: String, - commitment: String, - messageAuthenticationCode: String, - shortAuthenticationStrings: List<String>): VerificationInfoAccept = + override fun createAccept( + tid: String, + keyAgreementProtocol: String, + hash: String, + commitment: String, + messageAuthenticationCode: String, + shortAuthenticationStrings: List<String> + ): VerificationInfoAccept = MessageVerificationAcceptContent.create( tid, keyAgreementProtocol, @@ -207,12 +222,14 @@ internal class VerificationTransportRoomMessage( override fun createMac(tid: String, mac: Map<String, String>, keys: String) = MessageVerificationMacContent.create(tid, mac, keys) - override fun createStartForSas(fromDevice: String, - transactionId: String, - keyAgreementProtocols: List<String>, - hashes: List<String>, - messageAuthenticationCodes: List<String>, - shortAuthenticationStrings: List<String>): VerificationInfoStart { + override fun createStartForSas( + fromDevice: String, + transactionId: String, + keyAgreementProtocols: List<String>, + hashes: List<String>, + messageAuthenticationCodes: List<String>, + shortAuthenticationStrings: List<String> + ): VerificationInfoStart { return MessageVerificationStartContent( fromDevice, hashes, @@ -228,9 +245,11 @@ internal class VerificationTransportRoomMessage( ) } - override fun createStartForQrCode(fromDevice: String, - transactionId: String, - sharedSecret: String): VerificationInfoStart { + override fun createStartForQrCode( + fromDevice: String, + transactionId: String, + sharedSecret: String + ): VerificationInfoStart { return MessageVerificationStartContent( fromDevice, null, @@ -271,10 +290,12 @@ internal class VerificationTransportRoomMessage( } } - override fun sendVerificationReady(keyReq: VerificationInfoReady, - otherUserId: String, - otherDeviceId: String?, - callback: (() -> Unit)?) { + override fun sendVerificationReady( + keyReq: VerificationInfoReady, + otherUserId: String, + otherDeviceId: String?, + callback: (() -> Unit)? + ) { // Not applicable (send event is called directly) Timber.w("## SAS ignored verification ready with methods: ${keyReq.methods}") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt index bc24ef2966ef5e6b9549517568b973430328d58b..861a7a3a77a3a6300571b3dd06505ad7fc320ecf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt @@ -47,12 +47,14 @@ internal class VerificationTransportToDevice( private val clock: Clock, ) : VerificationTransport { - override fun sendVerificationRequest(supportedMethods: List<String>, - localId: String, - otherUserId: String, - roomId: String?, - toDevices: List<String>?, - callback: (String?, ValidVerificationInfoRequest?) -> Unit) { + override fun sendVerificationRequest( + supportedMethods: List<String>, + localId: String, + otherUserId: String, + roomId: String?, + toDevices: List<String>?, + callback: (String?, ValidVerificationInfoRequest?) -> Unit + ) { Timber.d("## SAS sending verification request with supported methods: $supportedMethods") val contentMap = MXUsersDevicesMap<Any>() val validKeyReq = ValidVerificationInfoRequest( @@ -86,10 +88,12 @@ internal class VerificationTransportToDevice( .executeBy(taskExecutor) } - override fun sendVerificationReady(keyReq: VerificationInfoReady, - otherUserId: String, - otherDeviceId: String?, - callback: (() -> Unit)?) { + override fun sendVerificationReady( + keyReq: VerificationInfoReady, + otherUserId: String, + otherDeviceId: String?, + callback: (() -> Unit)? + ) { Timber.d("## SAS sending verification ready with methods: ${keyReq.methods}") val contentMap = MXUsersDevicesMap<Any>() @@ -111,11 +115,13 @@ internal class VerificationTransportToDevice( .executeBy(taskExecutor) } - override fun <T> sendToOther(type: String, - verificationInfo: VerificationInfo<T>, - nextState: VerificationTxState, - onErrorReason: CancelCode, - onDone: (() -> Unit)?) { + override fun <T> sendToOther( + type: String, + verificationInfo: VerificationInfo<T>, + nextState: VerificationTxState, + onErrorReason: CancelCode, + onDone: (() -> Unit)? + ) { Timber.d("## SAS sending msg type $type") Timber.v("## SAS sending msg info $verificationInfo") val stateBeforeCall = tx?.state @@ -193,12 +199,35 @@ internal class VerificationTransportToDevice( .executeBy(taskExecutor) } - override fun createAccept(tid: String, - keyAgreementProtocol: String, - hash: String, - commitment: String, - messageAuthenticationCode: String, - shortAuthenticationStrings: List<String>): VerificationInfoAccept = KeyVerificationAccept.create( + override fun cancelTransaction(transactionId: String, otherUserId: String, otherUserDeviceIds: List<String>, code: CancelCode) { + Timber.d("## SAS canceling transaction $transactionId for reason $code") + val cancelMessage = KeyVerificationCancel.create(transactionId, code) + val contentMap = MXUsersDevicesMap<Any>() + val messages = otherUserDeviceIds.associateWith { cancelMessage } + contentMap.setObjects(otherUserId, messages) + sendToDeviceTask + .configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap)) { + this.callback = object : MatrixCallback<Unit> { + override fun onSuccess(data: Unit) { + Timber.v("## SAS verification [$transactionId] canceled for reason ${code.value}") + } + + override fun onFailure(failure: Throwable) { + Timber.e(failure, "## SAS verification [$transactionId] failed to cancel.") + } + } + } + .executeBy(taskExecutor) + } + + override fun createAccept( + tid: String, + keyAgreementProtocol: String, + hash: String, + commitment: String, + messageAuthenticationCode: String, + shortAuthenticationStrings: List<String> + ): VerificationInfoAccept = KeyVerificationAccept.create( tid, keyAgreementProtocol, hash, @@ -211,12 +240,14 @@ internal class VerificationTransportToDevice( override fun createMac(tid: String, mac: Map<String, String>, keys: String) = KeyVerificationMac.create(tid, mac, keys) - override fun createStartForSas(fromDevice: String, - transactionId: String, - keyAgreementProtocols: List<String>, - hashes: List<String>, - messageAuthenticationCodes: List<String>, - shortAuthenticationStrings: List<String>): VerificationInfoStart { + override fun createStartForSas( + fromDevice: String, + transactionId: String, + keyAgreementProtocols: List<String>, + hashes: List<String>, + messageAuthenticationCodes: List<String>, + shortAuthenticationStrings: List<String> + ): VerificationInfoStart { return KeyVerificationStart( fromDevice, VERIFICATION_METHOD_SAS, @@ -229,9 +260,11 @@ internal class VerificationTransportToDevice( ) } - override fun createStartForQrCode(fromDevice: String, - transactionId: String, - sharedSecret: String): VerificationInfoStart { + override fun createStartForQrCode( + fromDevice: String, + transactionId: String, + sharedSecret: String + ): VerificationInfoStart { return KeyVerificationStart( fromDevice, VERIFICATION_METHOD_RECIPROCATE, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt index b1ad4d87b6a56acec89926cb826b7692ea48e96d..690ac122687c5835e38b7c673cfbd8a2a1ca3f16 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt @@ -94,7 +94,7 @@ internal class DefaultQrCodeVerificationTransaction( // Check the other device view of my MSK when (otherQrCodeData) { - is QrCodeData.VerifyingAnotherUser -> { + is QrCodeData.VerifyingAnotherUser -> { // key2 (aka otherUserMasterCrossSigningPublicKey) is what the one displaying the QR code (other user) think my MSK is. // Let's check that it's correct // If not -> Cancel @@ -104,7 +104,7 @@ internal class DefaultQrCodeVerificationTransaction( return } else Unit } - is QrCodeData.SelfVerifyingMasterKeyTrusted -> { + is QrCodeData.SelfVerifyingMasterKeyTrusted -> { // key1 (aka userMasterCrossSigningPublicKey) is the session displaying the QR code view of our MSK. // Let's check that I see the same MSK // If not -> Cancel @@ -135,7 +135,7 @@ internal class DefaultQrCodeVerificationTransaction( // Let's now check the other user/device key material when (otherQrCodeData) { - is QrCodeData.VerifyingAnotherUser -> { + is QrCodeData.VerifyingAnotherUser -> { // key1(aka userMasterCrossSigningPublicKey) is the MSK of the one displaying the QR code (i.e other user) // Let's check that it matches what I think it should be if (otherQrCodeData.userMasterCrossSigningPublicKey @@ -149,7 +149,7 @@ internal class DefaultQrCodeVerificationTransaction( Unit } } - is QrCodeData.SelfVerifyingMasterKeyTrusted -> { + is QrCodeData.SelfVerifyingMasterKeyTrusted -> { // key2 (aka otherDeviceKey) is my current device key in POV of the one displaying the QR code (i.e other device) // Let's check that it's correct if (otherQrCodeData.otherDeviceKey @@ -259,11 +259,11 @@ internal class DefaultQrCodeVerificationTransaction( override fun otherUserScannedMyQrCode() { when (qrCodeData) { - is QrCodeData.VerifyingAnotherUser -> { + is QrCodeData.VerifyingAnotherUser -> { // Alice telling Bob that the code was scanned successfully is sufficient for Bob to trust Alice's key, trust(true, emptyList(), false) } - is QrCodeData.SelfVerifyingMasterKeyTrusted -> { + is QrCodeData.SelfVerifyingMasterKeyTrusted -> { // I now know that I have the correct device key for other session, // and can sign it with the self-signing key and upload the signature trust(false, listOf(otherDeviceId ?: ""), false) @@ -272,7 +272,7 @@ internal class DefaultQrCodeVerificationTransaction( // I now know that i can trust my MSK trust(true, emptyList(), true) } - null -> Unit + null -> Unit } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt index b80c29c244af1b3b057dda558a4d8f47329c346d..a0202485d62c4461167631cc98f9579581293253 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/Extensions.kt @@ -36,8 +36,8 @@ internal fun QrCodeData.toEncodedString(): String { // Mode result += when (this) { - is QrCodeData.VerifyingAnotherUser -> 0 - is QrCodeData.SelfVerifyingMasterKeyTrusted -> 1 + is QrCodeData.VerifyingAnotherUser -> 0 + is QrCodeData.SelfVerifyingMasterKeyTrusted -> 1 is QrCodeData.SelfVerifyingMasterKeyNotTrusted -> 2 }.toByte() @@ -119,9 +119,9 @@ internal fun String.toQrCodeData(): QrCodeData? { val secret = byteArray.copyOfRange(cursor, byteArray.size).toBase64NoPadding() return when (mode) { - 0 -> QrCodeData.VerifyingAnotherUser(transactionId, key1, key2, secret) - 1 -> QrCodeData.SelfVerifyingMasterKeyTrusted(transactionId, key1, key2, secret) - 2 -> QrCodeData.SelfVerifyingMasterKeyNotTrusted(transactionId, key1, key2, secret) + 0 -> QrCodeData.VerifyingAnotherUser(transactionId, key1, key2, secret) + 1 -> QrCodeData.SelfVerifyingMasterKeyTrusted(transactionId, key1, key2, secret) + 2 -> QrCodeData.SelfVerifyingMasterKeyNotTrusted(transactionId, key1, key2, secret) else -> null } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt index 751992fa7f8839c614dd11a2eeb5c219679ef66f..d1ca4f48a6608cc1110dee4d21cbc72e83aacc57 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/EventInsertLiveObserver.kt @@ -19,10 +19,9 @@ package org.matrix.android.sdk.internal.database import com.zhuinden.monarchy.Monarchy import io.realm.RealmConfiguration import io.realm.RealmResults -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import org.matrix.android.sdk.internal.database.mapper.asDomain import org.matrix.android.sdk.internal.database.model.EventEntity import org.matrix.android.sdk.internal.database.model.EventInsertEntity @@ -33,69 +32,64 @@ import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor import timber.log.Timber import javax.inject.Inject -internal class EventInsertLiveObserver @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration, - private val processors: Set<@JvmSuppressWildcards EventInsertLiveProcessor>) : +internal class EventInsertLiveObserver @Inject constructor( + @SessionDatabase realmConfiguration: RealmConfiguration, + private val processors: Set<@JvmSuppressWildcards EventInsertLiveProcessor> +) : RealmLiveEntityObserver<EventInsertEntity>(realmConfiguration) { + private val lock = Mutex() + override val query = Monarchy.Query { it.where(EventInsertEntity::class.java).equalTo(EventInsertEntityFields.CAN_BE_PROCESSED, true) } - private val onResultsChangedFlow = MutableSharedFlow<RealmResults<EventInsertEntity>>() - - init { - onResultsChangedFlow - .onEach { handleChange(it) } - .launchIn(observerScope) - } - override fun onChange(results: RealmResults<EventInsertEntity>) { - if (!results.isLoaded || results.isEmpty()) { - return - } - observerScope.launch { onResultsChangedFlow.emit(results) } - } - - private suspend fun handleChange(results: RealmResults<EventInsertEntity>) { - val idsToDeleteAfterProcess = ArrayList<String>() - val filteredEvents = ArrayList<EventInsertEntity>(results.size) - Timber.v("EventInsertEntity updated with ${results.size} results in db") - results.forEach { - if (shouldProcess(it)) { - // don't use copy from realm over there - val copiedEvent = EventInsertEntity( - eventId = it.eventId, - eventType = it.eventType - ).apply { - insertType = it.insertType + observerScope.launch { + lock.withLock { + if (!results.isLoaded || results.isEmpty()) { + return@withLock } - filteredEvents.add(copiedEvent) - } - idsToDeleteAfterProcess.add(it.eventId) - } - - awaitTransaction(realmConfiguration) { realm -> - Timber.v("##Transaction: There are ${filteredEvents.size} events to process ") - filteredEvents.forEach { eventInsert -> - val eventId = eventInsert.eventId - val event = EventEntity.where(realm, eventId).findFirst() - if (event == null) { - Timber.v("Event $eventId not found") - return@forEach + val idsToDeleteAfterProcess = ArrayList<String>() + val filteredEvents = ArrayList<EventInsertEntity>(results.size) + Timber.v("EventInsertEntity updated with ${results.size} results in db") + results.forEach { + if (shouldProcess(it)) { + // don't use copy from realm over there + val copiedEvent = EventInsertEntity( + eventId = it.eventId, + eventType = it.eventType + ).apply { + insertType = it.insertType + } + filteredEvents.add(copiedEvent) + } + idsToDeleteAfterProcess.add(it.eventId) } - val domainEvent = event.asDomain() - processors.filter { - it.shouldProcess(eventId, domainEvent.getClearType(), eventInsert.insertType) - }.forEach { - it.process(realm, domainEvent) + awaitTransaction(realmConfiguration) { realm -> + Timber.v("##Transaction: There are ${filteredEvents.size} events to process ") + filteredEvents.forEach { eventInsert -> + val eventId = eventInsert.eventId + val event = EventEntity.where(realm, eventId).findFirst() + if (event == null) { + Timber.v("Event $eventId not found") + return@forEach + } + val domainEvent = event.asDomain() + processors.filter { + it.shouldProcess(eventId, domainEvent.getClearType(), eventInsert.insertType) + }.forEach { + it.process(realm, domainEvent) + } + } + realm.where(EventInsertEntity::class.java) + .`in`(EventInsertEntityFields.EVENT_ID, idsToDeleteAfterProcess.toTypedArray()) + .findAll() + .deleteAllFromRealm() } + processors.forEach { it.onPostProcess() } } - realm.where(EventInsertEntity::class.java) - .`in`(EventInsertEntityFields.EVENT_ID, idsToDeleteAfterProcess.toTypedArray()) - .findAll() - .deleteAllFromRealm() } - processors.forEach { it.onPostProcess() } } private fun shouldProcess(eventInsertEntity: EventInsertEntity): Boolean { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt index 392c1a7185a98df3ac69dc0af04faae422df5570..b3a039d11927f9badf9b04d7df0980acd4c964ba 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmKeysUtils.kt @@ -38,8 +38,10 @@ import javax.inject.Inject * then we generate a random secret key. The database key is encrypted with the secret key; The secret * key is encrypted with the public RSA key and stored with the encrypted key in the shared pref */ -internal class RealmKeysUtils @Inject constructor(context: Context, - private val secretStoringUtils: SecretStoringUtils) { +internal class RealmKeysUtils @Inject constructor( + context: Context, + private val secretStoringUtils: SecretStoringUtils +) { private val rng = SecureRandom() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmQueryLatch.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmQueryLatch.kt index c9c797304ad7e52089402bda6af90735b26cf43d..c5ca861e9bdd4ecf0d642a9f6304ce63eb838cfe 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmQueryLatch.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmQueryLatch.kt @@ -27,9 +27,11 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeout -internal suspend fun <T> awaitNotEmptyResult(realmConfiguration: RealmConfiguration, - timeoutMillis: Long, - builder: (Realm) -> RealmQuery<T>) { +internal suspend fun <T> awaitNotEmptyResult( + realmConfiguration: RealmConfiguration, + timeoutMillis: Long, + builder: (Realm) -> RealmQuery<T> +) { withTimeout(timeoutMillis) { // Confine Realm interaction to a single thread with Looper. withContext(Dispatchers.Main) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index 55bccfd1ec69775d60c2d951cab7fe37a5dad786..6a8589bc5e26bafdd377cab9b15a055b6e7223e9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -46,6 +46,8 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo025 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo026 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo027 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo028 +import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo029 +import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo030 import org.matrix.android.sdk.internal.util.Normalizer import timber.log.Timber import javax.inject.Inject @@ -60,7 +62,7 @@ internal class RealmSessionStoreMigration @Inject constructor( override fun equals(other: Any?) = other is RealmSessionStoreMigration override fun hashCode() = 1000 - val schemaVersion = 28L + val schemaVersion = 30L override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { Timber.d("Migrating Realm Session from $oldVersion to $newVersion") @@ -93,5 +95,7 @@ internal class RealmSessionStoreMigration @Inject constructor( if (oldVersion < 26) MigrateSessionTo026(realm).perform() if (oldVersion < 27) MigrateSessionTo027(realm).perform() if (oldVersion < 28) MigrateSessionTo028(realm).perform() + if (oldVersion < 29) MigrateSessionTo029(realm).perform() + if (oldVersion < 30) MigrateSessionTo030(realm).perform() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt index 08d55b5647fac964c05945963e98599f3c67a705..949dd5daa1de60d76e2cd0f087c411a2d9b1f632 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt @@ -44,7 +44,8 @@ internal class SessionRealmConfigurationFactory @Inject constructor( @SessionFilesDirectory val directory: File, @SessionId val sessionId: String, @UserMd5 val userMd5: String, - context: Context) { + context: Context +) { // Keep legacy preferences name for compatibility reason private val sharedPreferences = context.getSharedPreferences("im.vector.matrix.android.realm", Context.MODE_PRIVATE) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt index caaf6b81100ce609bf37c09213522768f77db7b8..234caec970df92d5d201e0fdec4146615642d151 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt @@ -17,7 +17,6 @@ package org.matrix.android.sdk.internal.database.helper import io.realm.Realm -import io.realm.Sort import io.realm.kotlin.createObject import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.internal.database.model.ChunkEntity @@ -34,32 +33,9 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.database.query.find import org.matrix.android.sdk.internal.database.query.getOrCreate import org.matrix.android.sdk.internal.database.query.where -import org.matrix.android.sdk.internal.database.query.whereRoomId -import org.matrix.android.sdk.internal.extensions.assertIsManaged import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection import timber.log.Timber -internal fun ChunkEntity.merge(roomId: String, chunkToMerge: ChunkEntity, direction: PaginationDirection) { - assertIsManaged() - val localRealm = this.realm - val eventsToMerge: List<TimelineEventEntity> - if (direction == PaginationDirection.FORWARDS) { - this.nextToken = chunkToMerge.nextToken - this.isLastForward = chunkToMerge.isLastForward - eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING) - } else { - this.prevToken = chunkToMerge.prevToken - this.isLastBackward = chunkToMerge.isLastBackward - eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING) - } - chunkToMerge.stateEvents.forEach { stateEvent -> - addStateEvent(roomId, stateEvent, direction) - } - eventsToMerge.forEach { - addTimelineEventFromMerge(localRealm, it, direction) - } -} - internal fun ChunkEntity.addStateEvent(roomId: String, stateEvent: EventEntity, direction: PaginationDirection) { if (direction == PaginationDirection.BACKWARDS) { Timber.v("We don't keep chunk state events when paginating backward") @@ -79,11 +55,13 @@ internal fun ChunkEntity.addStateEvent(roomId: String, stateEvent: EventEntity, } } -internal fun ChunkEntity.addTimelineEvent(roomId: String, - eventEntity: EventEntity, - direction: PaginationDirection, - ownedByThreadChunk: Boolean = false, - roomMemberContentsByUser: Map<String, RoomMemberContent?>? = null): TimelineEventEntity? { +internal fun ChunkEntity.addTimelineEvent( + roomId: String, + eventEntity: EventEntity, + direction: PaginationDirection, + ownedByThreadChunk: Boolean = false, + roomMemberContentsByUser: Map<String, RoomMemberContent?>? = null +): TimelineEventEntity? { val eventId = eventEntity.eventId if (timelineEvents.find(eventId) != null) { return null @@ -142,40 +120,6 @@ internal fun computeIsUnique( } } -private fun ChunkEntity.addTimelineEventFromMerge(realm: Realm, timelineEventEntity: TimelineEventEntity, direction: PaginationDirection) { - val eventId = timelineEventEntity.eventId - if (timelineEvents.find(eventId) != null) { - return - } - val displayIndex = nextDisplayIndex(direction) - val localId = TimelineEventEntity.nextId(realm) - val copied = realm.createObject<TimelineEventEntity>().apply { - this.localId = localId - this.root = timelineEventEntity.root - this.eventId = timelineEventEntity.eventId - this.roomId = timelineEventEntity.roomId - this.annotations = timelineEventEntity.annotations - this.readReceipts = timelineEventEntity.readReceipts - this.displayIndex = displayIndex - this.senderAvatar = timelineEventEntity.senderAvatar - this.senderName = timelineEventEntity.senderName - this.isUniqueDisplayName = timelineEventEntity.isUniqueDisplayName - } - handleThreadSummary(realm, eventId, copied) - timelineEvents.add(copied) -} - -/** - * Upon copy of the timeline events we should update the latestMessage TimelineEventEntity with the new one. - */ -private fun handleThreadSummary(realm: Realm, oldEventId: String, newTimelineEventEntity: TimelineEventEntity) { - EventEntity - .whereRoomId(realm, newTimelineEventEntity.roomId) - .equalTo(EventEntityFields.IS_ROOT_THREAD, true) - .equalTo(EventEntityFields.THREAD_SUMMARY_LATEST_MESSAGE.EVENT_ID, oldEventId) - .findFirst()?.threadSummaryLatestMessage = newTimelineEventEntity -} - private fun handleReadReceipts(realm: Realm, roomId: String, eventEntity: EventEntity, senderId: String): ReadReceiptsSummaryEntity { val readReceiptsSummaryEntity = ReadReceiptsSummaryEntity.where(realm, eventEntity.eventId).findFirst() ?: realm.createObject<ReadReceiptsSummaryEntity>(eventEntity.eventId).apply { @@ -199,7 +143,7 @@ private fun handleReadReceipts(realm: Realm, roomId: String, eventEntity: EventE internal fun ChunkEntity.nextDisplayIndex(direction: PaginationDirection): Int { return when (direction) { - PaginationDirection.FORWARDS -> { + PaginationDirection.FORWARDS -> { (timelineEvents.where().max(TimelineEventEntityFields.DISPLAY_INDEX)?.toInt() ?: 0) + 1 } PaginationDirection.BACKWARDS -> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadEventsHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadEventsHelper.kt index db3647c3fae24312b899091329e4a7c4b7aea074..dfac7f670878aa1cfa298809395022f1032f6576 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadEventsHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadEventsHelper.kt @@ -47,9 +47,11 @@ private typealias Summary = Pair<Int, TimelineEventEntity>? */ internal fun Map<String, EventEntity>.updateThreadSummaryIfNeeded( roomId: String, - realm: Realm, currentUserId: String, + realm: Realm, + currentUserId: String, chunkEntity: ChunkEntity? = null, - shouldUpdateNotifications: Boolean = true) { + shouldUpdateNotifications: Boolean = true +) { for ((rootThreadEventId, eventEntity) in this) { eventEntity.threadSummaryInThread(eventEntity.realm, rootThreadEventId, chunkEntity)?.let { threadSummary -> @@ -87,7 +89,8 @@ internal fun EventEntity.findRootThreadEvent(): EventEntity? = */ internal fun EventEntity.markEventAsRoot( inThreadMessages: Int, - latestMessageTimelineEventEntity: TimelineEventEntity?) { + latestMessageTimelineEventEntity: TimelineEventEntity? +) { isRootThread = true numberOfThreads = inThreadMessages threadSummaryLatestMessage = latestMessageTimelineEventEntity @@ -96,7 +99,9 @@ internal fun EventEntity.markEventAsRoot( /** * Count the number of threads for the provided root thread eventId, and finds the latest event message. * Note: Redactions are handled by RedactionEventProcessor. + * @param realm the realm database * @param rootThreadEventId The root eventId that will find the number of threads + * @param chunkEntity the chunk entity * @return A ThreadSummary containing the counted threads and the latest event message */ internal fun EventEntity.threadSummaryInThread(realm: Realm, rootThreadEventId: String, chunkEntity: ChunkEntity?): Summary { @@ -184,6 +189,7 @@ private fun findLatestSortedChunkEvent(chunk: ChunkEntity, rootThreadEventId: St /** * Find all TimelineEventEntity that are root threads for the specified room. + * @param realm the realm instance * @param roomId The room that all stored root threads will be returned */ internal fun TimelineEventEntity.Companion.findAllThreadsForRoomId(realm: Realm, roomId: String): RealmQuery<TimelineEventEntity> = @@ -218,6 +224,7 @@ internal fun List<TimelineEvent>.mapEventsWithEdition(realm: Realm, roomId: Stri /** * Returns a list of all the marked unread threads that exists for the specified room. + * @param realm the realm instance * @param roomId The roomId that the user is currently in */ internal fun TimelineEventEntity.Companion.findAllLocalThreadNotificationsForRoomId(realm: Realm, roomId: String): RealmQuery<TimelineEventEntity> = @@ -232,6 +239,7 @@ internal fun TimelineEventEntity.Companion.findAllLocalThreadNotificationsForRoo /** * Returns whether or not the given user is participating in a current thread. + * @param realm the realm instance * @param roomId the room that the thread exists * @param rootThreadEventId the thread that the search will be done * @param senderId the user that will try to find participation @@ -247,6 +255,7 @@ internal fun TimelineEventEntity.Companion.isUserParticipatingInThread(realm: Re /** * Returns whether or not the given user is mentioned in a current thread. + * @param realm the realm instance * @param roomId the room that the thread exists * @param rootThreadEventId the thread that the search will be done * @param userId the user that will try to find if there is a mention diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt index 3bf574c207db20f12d2949e2398426834e39b704..79a99cdfac4c282d5d9877fed8ba7278a930ab59 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt @@ -54,7 +54,8 @@ internal fun ThreadSummaryEntity.updateThreadSummary( numberOfThreads: Int?, latestThreadEventEntity: EventEntity?, isUserParticipating: Boolean, - roomMemberContentsByUser: HashMap<String, RoomMemberContent?>) { + roomMemberContentsByUser: HashMap<String, RoomMemberContent?> +) { updateThreadSummaryRootEvent(rootThreadEventEntity, roomMemberContentsByUser) updateThreadSummaryLatestEvent(latestThreadEventEntity, roomMemberContentsByUser) this.isUserParticipating = isUserParticipating @@ -180,7 +181,7 @@ internal fun ThreadSummaryEntity.Companion.createOrUpdate( roomEntity.addIfNecessary(threadSummary) } - ThreadSummaryUpdateType.ADD -> { + ThreadSummaryUpdateType.ADD -> { val rootThreadEventId = threadEventEntity?.rootThreadEventId ?: return Timber.i("###THREADS ThreadSummaryHelper ADD for root eventId:$rootThreadEventId") @@ -303,6 +304,7 @@ private fun getLatestEvent(rootThreadEvent: Event): Event? { /** * Find all ThreadSummaryEntity for the specified roomId, sorted by origin server. * note: Sorting cannot be provided by server, so we have to use that unstable property. + * @param realm the realm instance * @param roomId The id of the room */ internal fun ThreadSummaryEntity.Companion.findAllThreadsForRoomId(realm: Realm, roomId: String): RealmQuery<ThreadSummaryEntity> = diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/DraftMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/DraftMapper.kt index a00a2a8ee111d189741323704b23a465d0d2abd7..4cf2ef6723ed0518107ace1bc0255f71a1cb4304 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/DraftMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/DraftMapper.kt @@ -27,21 +27,21 @@ internal object DraftMapper { fun map(entity: DraftEntity): UserDraft { return when (entity.draftMode) { DraftEntity.MODE_REGULAR -> UserDraft.Regular(entity.content) - DraftEntity.MODE_EDIT -> UserDraft.Edit(entity.linkedEventId, entity.content) - DraftEntity.MODE_QUOTE -> UserDraft.Quote(entity.linkedEventId, entity.content) - DraftEntity.MODE_REPLY -> UserDraft.Reply(entity.linkedEventId, entity.content) - DraftEntity.MODE_VOICE -> UserDraft.Voice(entity.content) - else -> null + DraftEntity.MODE_EDIT -> UserDraft.Edit(entity.linkedEventId, entity.content) + DraftEntity.MODE_QUOTE -> UserDraft.Quote(entity.linkedEventId, entity.content) + DraftEntity.MODE_REPLY -> UserDraft.Reply(entity.linkedEventId, entity.content) + DraftEntity.MODE_VOICE -> UserDraft.Voice(entity.content) + else -> null } ?: UserDraft.Regular("") } fun map(domain: UserDraft): DraftEntity { return when (domain) { is UserDraft.Regular -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_REGULAR, linkedEventId = "") - is UserDraft.Edit -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_EDIT, linkedEventId = domain.linkedEventId) - is UserDraft.Quote -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_QUOTE, linkedEventId = domain.linkedEventId) - is UserDraft.Reply -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_REPLY, linkedEventId = domain.linkedEventId) - is UserDraft.Voice -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_VOICE, linkedEventId = "") + is UserDraft.Edit -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_EDIT, linkedEventId = domain.linkedEventId) + is UserDraft.Quote -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_QUOTE, linkedEventId = domain.linkedEventId) + is UserDraft.Reply -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_REPLY, linkedEventId = domain.linkedEventId) + is UserDraft.Voice -> DraftEntity(content = domain.content, draftMode = DraftEntity.MODE_VOICE, linkedEventId = "") } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt index c747ad334fee19ff858b40b69edfe901149b6236..6bbeb17fdd021af5a9a9123c01e946999d95320e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt @@ -58,7 +58,7 @@ internal object EventAnnotationsSummaryMapper { PollResponseAggregatedSummaryEntityMapper.map(it) }, liveLocationShareAggregatedSummary = annotationsSummary.liveLocationShareAggregatedSummary?.let { - LiveLocationShareAggregatedSummaryMapper.map(it) + LiveLocationShareAggregatedSummaryMapper().map(it) } ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt index bc7d40bf6f1dcec8977063f41d4b92197d8ce9aa..5b60c536425155562f3cfad3528e5a3793eb9f7b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventMapper.kt @@ -127,10 +127,12 @@ internal fun EventEntity.asDomain(castJsonNumbers: Boolean = false): Event { return EventMapper.map(this, castJsonNumbers) } -internal fun Event.toEntity(roomId: String, - sendState: SendState, - ageLocalTs: Long?, - contentToInject: String? = null): EventEntity { +internal fun Event.toEntity( + roomId: String, + sendState: SendState, + ageLocalTs: Long?, + contentToInject: String? = null +): EventEntity { return EventMapper.map(this, roomId).apply { this.sendState = sendState this.ageLocalTs = ageLocalTs diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/IsUselessResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/IsUselessResolver.kt index d704ecac8e0a61fa65905dc95c110587b605235e..1a4821e80c53f6d503d36dcac213634995d828a7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/IsUselessResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/IsUselessResolver.kt @@ -32,7 +32,7 @@ internal object IsUselessResolver { event.content != null && event.content.toContent() == event.resolvedPrevContent()?.toContent() } - else -> false + else -> false } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt index 71b36f88bd8f30a60f01c2e8655e094850a80de4..9460e4c6ba228a5264826819c88fc9e760b2d349 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapper.kt @@ -20,11 +20,13 @@ import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity +import javax.inject.Inject -internal object LiveLocationShareAggregatedSummaryMapper { +internal class LiveLocationShareAggregatedSummaryMapper @Inject constructor() { fun map(entity: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary { return LiveLocationShareAggregatedSummary( + userId = entity.userId, isActive = entity.isActive, endOfLiveTimestampMillis = entity.endOfLiveTimestampMillis, lastLocationDataContent = ContentMapper.map(entity.lastLocationContent).toModel<MessageBeaconLocationDataContent>() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt index 41faf30a82e726c56290521151b7e8ce2a7ce811..735cfe411ce67b2b695652b3fd35e5dc78b93cf5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt @@ -29,8 +29,10 @@ import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity import org.matrix.android.sdk.internal.database.model.presence.toUserPresence import javax.inject.Inject -internal class RoomSummaryMapper @Inject constructor(private val timelineEventMapper: TimelineEventMapper, - private val typingUsersTracker: TypingUsersTracker) { +internal class RoomSummaryMapper @Inject constructor( + private val timelineEventMapper: TimelineEventMapper, + private val typingUsersTracker: TypingUsersTracker +) { fun map(roomSummaryEntity: RoomSummaryEntity): RoomSummary { val tags = roomSummaryEntity.tags().map { @@ -109,7 +111,7 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa // I should probably use #hasEncryptorClassForAlgorithm but it says it supports // OLM which is some legacy? Now only megolm allowed in rooms MXCRYPTO_ALGORITHM_MEGOLM -> RoomEncryptionAlgorithm.Megolm - else -> RoomEncryptionAlgorithm.UnsupportedAlgorithm(alg) + else -> RoomEncryptionAlgorithm.UnsupportedAlgorithm(alg) } ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo019.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo019.kt index 754a66bb4b9de9059aa0fadc98e8c010a57acdd8..38de70cc7ca1ec487417ec8d099a09962d2161d0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo019.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo019.kt @@ -21,8 +21,10 @@ import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields import org.matrix.android.sdk.internal.util.Normalizer import org.matrix.android.sdk.internal.util.database.RealmMigrator -internal class MigrateSessionTo019(realm: DynamicRealm, - private val normalizer: Normalizer) : RealmMigrator(realm, 19) { +internal class MigrateSessionTo019( + realm: DynamicRealm, + private val normalizer: Normalizer +) : RealmMigrator(realm, 19) { override fun doMigrate(realm: DynamicRealm) { realm.schema.get("RoomSummaryEntity") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt new file mode 100644 index 0000000000000000000000000000000000000000..aebca11c2bb3b409057d09de82dbe8d508d42604 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo029.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.database.migration + +import io.realm.DynamicRealm +import io.realm.FieldAttribute +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields +import org.matrix.android.sdk.internal.util.database.RealmMigrator + +/** + * Migrating to: + * Live location sharing aggregated summary: adding new field userId. + */ +internal class MigrateSessionTo029(realm: DynamicRealm) : RealmMigrator(realm, 28) { + + override fun doMigrate(realm: DynamicRealm) { + realm.schema.get("LiveLocationShareAggregatedSummaryEntity") + ?.addField(LiveLocationShareAggregatedSummaryEntityFields.USER_ID, String::class.java, FieldAttribute.REQUIRED) + ?.transform { obj -> + obj.setString(LiveLocationShareAggregatedSummaryEntityFields.USER_ID, "") + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo030.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo030.kt new file mode 100644 index 0000000000000000000000000000000000000000..b9c611f5dde8c0d209229c60a3b8ba70759e3554 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo030.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.database.migration + +import io.realm.DynamicRealm +import org.matrix.android.sdk.internal.database.model.ChunkEntityFields +import org.matrix.android.sdk.internal.database.model.EventEntityFields +import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields +import org.matrix.android.sdk.internal.util.database.RealmMigrator +import timber.log.Timber + +/** + * Migrating to: + * Cleaning old chunks which may have broken links. + */ +internal class MigrateSessionTo030(realm: DynamicRealm) : RealmMigrator(realm, 30) { + + override fun doMigrate(realm: DynamicRealm) { + // Delete all previous chunks + val chunks = realm.where("ChunkEntity") + .equalTo(ChunkEntityFields.IS_LAST_FORWARD, false) + .findAll() + + val nbOfDeletedChunks = chunks.size + var nbOfDeletedTimelineEvents = 0 + var nbOfDeletedEvents = 0 + chunks.forEach { chunk -> + val timelineEvents = chunk.getList(ChunkEntityFields.TIMELINE_EVENTS.`$`) + timelineEvents.forEach { timelineEvent -> + // Don't delete state events + val event = timelineEvent.getObject(TimelineEventEntityFields.ROOT.`$`) + if (event?.isNull(EventEntityFields.STATE_KEY) == true) { + nbOfDeletedEvents++ + event.deleteFromRealm() + } + } + nbOfDeletedTimelineEvents += timelineEvents.size + timelineEvents.deleteAllFromRealm() + } + chunks.deleteAllFromRealm() + Timber.d("MigrateSessionTo030: $nbOfDeletedChunks deleted chunk(s), $nbOfDeletedTimelineEvents deleted TimelineEvent(s) and $nbOfDeletedEvents deleted Event(s).") + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ChunkEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ChunkEntity.kt index 8399d82d5d75821e55d769dd8c8d06baca2be775..e5360ce0b63c66a154e07b9be116aba10518e4c9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ChunkEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ChunkEntity.kt @@ -53,7 +53,8 @@ internal open class ChunkEntity( internal fun ChunkEntity.deleteOnCascade( deleteStateEvents: Boolean, - canDeleteRoot: Boolean) { + canDeleteRoot: Boolean +) { assertIsManaged() if (deleteStateEvents) { stateEvents.deleteAllFromRealm() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/CurrentStateEventEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/CurrentStateEventEntity.kt index 251b05772290da9491245b092eef029ae6fdde3c..9deef69dabaa5a02d37342cf3d94fa444c91a78f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/CurrentStateEventEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/CurrentStateEventEntity.kt @@ -20,11 +20,12 @@ package org.matrix.android.sdk.internal.database.model import io.realm.RealmObject import io.realm.annotations.Index -internal open class CurrentStateEventEntity(var eventId: String = "", - var root: EventEntity? = null, - @Index var roomId: String = "", - @Index var type: String = "", - @Index var stateKey: String = "" +internal open class CurrentStateEventEntity( + var eventId: String = "", + var root: EventEntity? = null, + @Index var roomId: String = "", + @Index var type: String = "", + @Index var stateKey: String = "" ) : RealmObject() { companion object } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/DraftEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/DraftEntity.kt index fd09da4448f61341c391d1ad2d42576cc38b57af..3c19d4d4435f2e75c64827572bbac0144499e1f5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/DraftEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/DraftEntity.kt @@ -18,9 +18,10 @@ package org.matrix.android.sdk.internal.database.model import io.realm.RealmObject -internal open class DraftEntity(var content: String = "", - var draftMode: String = MODE_REGULAR, - var linkedEventId: String = "" +internal open class DraftEntity( + var content: String = "", + var draftMode: String = MODE_REGULAR, + var linkedEventId: String = "" ) : RealmObject() { companion object { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt index ba80cc8302aec1d0da5568e7bc2edd67a667111e..8b5a211fbaba4d5a477baff5aec881a48f047765 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt @@ -25,28 +25,29 @@ import org.matrix.android.sdk.api.session.threads.ThreadNotificationState import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.extensions.assertIsManaged -internal open class EventEntity(@Index var eventId: String = "", - @Index var roomId: String = "", - @Index var type: String = "", - var content: String? = null, - var prevContent: String? = null, - var isUseless: Boolean = false, - @Index var stateKey: String? = null, - var originServerTs: Long? = null, - @Index var sender: String? = null, +internal open class EventEntity( + @Index var eventId: String = "", + @Index var roomId: String = "", + @Index var type: String = "", + var content: String? = null, + var prevContent: String? = null, + var isUseless: Boolean = false, + @Index var stateKey: String? = null, + var originServerTs: Long? = null, + @Index var sender: String? = null, // Can contain a serialized MatrixError - var sendStateDetails: String? = null, - var age: Long? = 0, - var unsignedData: String? = null, - var redacts: String? = null, - var decryptionResultJson: String? = null, - var ageLocalTs: Long? = null, + var sendStateDetails: String? = null, + var age: Long? = 0, + var unsignedData: String? = null, + var redacts: String? = null, + var decryptionResultJson: String? = null, + var ageLocalTs: Long? = null, // Thread related, no need to create a new Entity for performance - @Index var isRootThread: Boolean = false, - @Index var rootThreadEventId: String? = null, + @Index var isRootThread: Boolean = false, + @Index var rootThreadEventId: String? = null, // Number messages within the thread - var numberOfThreads: Int = 0, - var threadSummaryLatestMessage: TimelineEventEntity? = null + var numberOfThreads: Int = 0, + var threadSummaryLatestMessage: TimelineEventEntity? = null ) : RealmObject() { private var sendStateStr: String = SendState.UNKNOWN.name diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventInsertEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventInsertEntity.kt index 5cfd306d2f0fab6b4822c0dc2f47b3237cbe646c..eff332dc3a9916724c927a50109291afe19a64a3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventInsertEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventInsertEntity.kt @@ -22,13 +22,14 @@ import io.realm.RealmObject * This class is used to get notification on new events being inserted. It's to avoid realm getting slow when listening to insert * in EventEntity table. */ -internal open class EventInsertEntity(var eventId: String = "", - var eventType: String = "", - /** - * This flag will be used to filter EventInsertEntity in EventInsertLiveObserver. - * Currently it's set to false when the event content is encrypted. - */ - var canBeProcessed: Boolean = true +internal open class EventInsertEntity( + var eventId: String = "", + var eventType: String = "", + /** + * This flag will be used to filter EventInsertEntity in EventInsertLiveObserver. + * Currently it's set to false when the event content is encrypted. + */ + var canBeProcessed: Boolean = true ) : RealmObject() { private var insertTypeStr: String = EventInsertType.INCREMENTAL_SYNC.name diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupSummaryEntity.kt index 4ba45dcda2d19ef3df08e5223140891b00216410..d96514855976cf05b19a1b87534fdc742f4bd83f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/GroupSummaryEntity.kt @@ -21,12 +21,13 @@ import io.realm.RealmObject import io.realm.annotations.PrimaryKey import org.matrix.android.sdk.api.session.room.model.Membership -internal open class GroupSummaryEntity(@PrimaryKey var groupId: String = "", - var displayName: String = "", - var shortDescription: String = "", - var avatarUrl: String = "", - var roomIds: RealmList<String> = RealmList(), - var userIds: RealmList<String> = RealmList() +internal open class GroupSummaryEntity( + @PrimaryKey var groupId: String = "", + var displayName: String = "", + var shortDescription: String = "", + var avatarUrl: String = "", + var roomIds: RealmList<String> = RealmList(), + var userIds: RealmList<String> = RealmList() ) : RealmObject() { private var membershipStr: String = Membership.NONE.name diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ReadReceiptEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ReadReceiptEntity.kt index e01d849cc22563c1d9dd74199dd6505fb7ff04be..9623c95359718f81dd994a17573baa6d7b310015 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ReadReceiptEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ReadReceiptEntity.kt @@ -21,11 +21,12 @@ import io.realm.RealmResults import io.realm.annotations.LinkingObjects import io.realm.annotations.PrimaryKey -internal open class ReadReceiptEntity(@PrimaryKey var primaryKey: String = "", - var eventId: String = "", - var roomId: String = "", - var userId: String = "", - var originServerTs: Double = 0.0 +internal open class ReadReceiptEntity( + @PrimaryKey var primaryKey: String = "", + var eventId: String = "", + var roomId: String = "", + var userId: String = "", + var originServerTs: Double = 0.0 ) : RealmObject() { companion object diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt index d8e6b8af0faaa0fcc22562b10ec993bb6f01903c..d2116fa9b89ad8369dc0bb8eb996fd60004fdd3e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomEntity.kt @@ -24,11 +24,12 @@ import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntit import org.matrix.android.sdk.internal.database.query.findRootOrLatest import org.matrix.android.sdk.internal.extensions.assertIsManaged -internal open class RoomEntity(@PrimaryKey var roomId: String = "", - var chunks: RealmList<ChunkEntity> = RealmList(), - var sendingTimelineEvents: RealmList<TimelineEventEntity> = RealmList(), - var threadSummaries: RealmList<ThreadSummaryEntity> = RealmList(), - var accountData: RealmList<RoomAccountDataEntity> = RealmList() +internal open class RoomEntity( + @PrimaryKey var roomId: String = "", + var chunks: RealmList<ChunkEntity> = RealmList(), + var sendingTimelineEvents: RealmList<TimelineEventEntity> = RealmList(), + var threadSummaries: RealmList<ThreadSummaryEntity> = RealmList(), + var accountData: RealmList<RoomAccountDataEntity> = RealmList() ) : RealmObject() { private var membershipStr: String = Membership.NONE.name diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomMemberSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomMemberSummaryEntity.kt index a8a76d16811f661fcbf4f2ce2bbc9b8a9a43aa33..6fb9324fcd8c7e2b2ed77a30678ca40e2b418c9a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomMemberSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomMemberSummaryEntity.kt @@ -23,13 +23,14 @@ import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntity -internal open class RoomMemberSummaryEntity(@PrimaryKey var primaryKey: String = "", - @Index var userId: String = "", - @Index var roomId: String = "", - @Index var displayName: String? = null, - var avatarUrl: String? = null, - var reason: String? = null, - var isDirect: Boolean = false +internal open class RoomMemberSummaryEntity( + @PrimaryKey var primaryKey: String = "", + @Index var userId: String = "", + @Index var roomId: String = "", + @Index var displayName: String? = null, + var avatarUrl: String? = null, + var reason: String? = null, + var isDirect: Boolean = false ) : RealmObject() { private var membershipStr: String = Membership.NONE.name diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SyncEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SyncEntity.kt index a82ec41456b7f297bb7ab454458b0ec67643e614..ff261b80c19e1973526de0866cbded4236e83f94 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SyncEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SyncEntity.kt @@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.database.model import io.realm.RealmObject import io.realm.annotations.PrimaryKey -internal open class SyncEntity(var nextBatch: String? = null, - @PrimaryKey var id: Long = 0 +internal open class SyncEntity( + var nextBatch: String? = null, + @PrimaryKey var id: Long = 0 ) : RealmObject() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/TimelineEventEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/TimelineEventEntity.kt index 477c04fe518097b6aef604a9214b09ab52337cf8..c8f22dc2ccbe8950907c48a470b7f8223e5bd009 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/TimelineEventEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/TimelineEventEntity.kt @@ -22,20 +22,21 @@ import io.realm.annotations.Index import io.realm.annotations.LinkingObjects import org.matrix.android.sdk.internal.extensions.assertIsManaged -internal open class TimelineEventEntity(var localId: Long = 0, - @Index var eventId: String = "", - @Index var roomId: String = "", - @Index var displayIndex: Int = 0, - var root: EventEntity? = null, - var annotations: EventAnnotationsSummaryEntity? = null, - var senderName: String? = null, - var isUniqueDisplayName: Boolean = false, - var senderAvatar: String? = null, - var senderMembershipEventId: String? = null, +internal open class TimelineEventEntity( + var localId: Long = 0, + @Index var eventId: String = "", + @Index var roomId: String = "", + @Index var displayIndex: Int = 0, + var root: EventEntity? = null, + var annotations: EventAnnotationsSummaryEntity? = null, + var senderName: String? = null, + var isUniqueDisplayName: Boolean = false, + var senderAvatar: String? = null, + var senderMembershipEventId: String? = null, // ownedByThreadChunk indicates that the current TimelineEventEntity belongs // to a thread chunk and is a temporarily event. - var ownedByThreadChunk: Boolean = false, - var readReceipts: ReadReceiptsSummaryEntity? = null + var ownedByThreadChunk: Boolean = false, + var readReceipts: ReadReceiptsSummaryEntity? = null ) : RealmObject() { @LinkingObjects("timelineEvents") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserDraftsEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserDraftsEntity.kt index 2c778f979762a31ca76788697bf1ff14a9d83d0f..7ccfc6b104e3f029ad08c85e239c4d29898d1802 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserDraftsEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserDraftsEntity.kt @@ -24,7 +24,8 @@ import io.realm.annotations.LinkingObjects /** * Create a specific table to be able to do direct query on it and keep the draft ordered. */ -internal open class UserDraftsEntity(var userDrafts: RealmList<DraftEntity> = RealmList() +internal open class UserDraftsEntity( + var userDrafts: RealmList<DraftEntity> = RealmList() ) : RealmObject() { // Link to RoomSummaryEntity diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserEntity.kt index bd6e73582d837d00e9e0349ad0ca495d739b8092..3644d12ac9f2389032cf16846f9bb8a409471b7d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/UserEntity.kt @@ -19,9 +19,10 @@ package org.matrix.android.sdk.internal.database.model import io.realm.RealmObject import io.realm.annotations.PrimaryKey -internal open class UserEntity(@PrimaryKey var userId: String = "", - var displayName: String = "", - var avatarUrl: String = "" +internal open class UserEntity( + @PrimaryKey var userId: String = "", + var displayName: String = "", + var avatarUrl: String = "" ) : RealmObject() { companion object diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt index 4d0d2c5c64303cbbfc676c3ce419b3adcdc9e739..c5df8e933838d2eaf43b068aa9ccdac1405c662a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/livelocation/LiveLocationShareAggregatedSummaryEntity.kt @@ -31,6 +31,11 @@ internal open class LiveLocationShareAggregatedSummaryEntity( var roomId: String = "", + var userId: String = "", + + /** + * Indicate whether the live is currently running. + */ var isActive: Boolean? = null, var endOfLiveTimestampMillis: Long? = null, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/presence/UserPresenceEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/presence/UserPresenceEntity.kt index 5713337ec574fc9893ec2e91ee44ecca4259e9e8..8d808417c27e9bbf3f08bcd428e8e42bd167ce24 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/presence/UserPresenceEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/presence/UserPresenceEntity.kt @@ -21,12 +21,13 @@ import io.realm.annotations.PrimaryKey import org.matrix.android.sdk.api.session.presence.model.PresenceEnum import org.matrix.android.sdk.api.session.presence.model.UserPresence -internal open class UserPresenceEntity(@PrimaryKey var userId: String = "", - var lastActiveAgo: Long? = null, - var statusMessage: String? = null, - var isCurrentlyActive: Boolean? = null, - var avatarUrl: String? = null, - var displayName: String? = null +internal open class UserPresenceEntity( + @PrimaryKey var userId: String = "", + var lastActiveAgo: Long? = null, + var statusMessage: String? = null, + var isCurrentlyActive: Boolean? = null, + var avatarUrl: String? = null, + var displayName: String? = null ) : RealmObject() { var presence: PresenceEnum diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/threads/ThreadSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/threads/ThreadSummaryEntity.kt index ab9d66548ed418a47652a8f0f4944b084869c8aa..45f9e3aa209583959d20b964aab3bee87f6b3e3c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/threads/ThreadSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/threads/ThreadSummaryEntity.kt @@ -23,17 +23,18 @@ import io.realm.annotations.LinkingObjects import org.matrix.android.sdk.internal.database.model.EventEntity import org.matrix.android.sdk.internal.database.model.RoomEntity -internal open class ThreadSummaryEntity(@Index var rootThreadEventId: String? = "", - var rootThreadEventEntity: EventEntity? = null, - var latestThreadEventEntity: EventEntity? = null, - var rootThreadSenderName: String? = null, - var latestThreadSenderName: String? = null, - var rootThreadSenderAvatar: String? = null, - var latestThreadSenderAvatar: String? = null, - var rootThreadIsUniqueDisplayName: Boolean = false, - var isUserParticipating: Boolean = false, - var latestThreadIsUniqueDisplayName: Boolean = false, - var numberOfThreads: Int = 0 +internal open class ThreadSummaryEntity( + @Index var rootThreadEventId: String? = "", + var rootThreadEventEntity: EventEntity? = null, + var latestThreadEventEntity: EventEntity? = null, + var rootThreadSenderName: String? = null, + var latestThreadSenderName: String? = null, + var rootThreadSenderAvatar: String? = null, + var latestThreadSenderAvatar: String? = null, + var rootThreadIsUniqueDisplayName: Boolean = false, + var isUserParticipating: Boolean = false, + var latestThreadIsUniqueDisplayName: Boolean = false, + var numberOfThreads: Int = 0 ) : RealmObject() { @LinkingObjects("threadSummaries") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt index 9350102137042b6b35c6e94762143f9c07da0914..1e5d96b4964f4246045428aa7ca6a97e1c1af999 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ChunkEntityQueries.kt @@ -31,6 +31,7 @@ internal fun ChunkEntity.Companion.where(realm: Realm, roomId: String): RealmQue internal fun ChunkEntity.Companion.find(realm: Realm, roomId: String, prevToken: String? = null, nextToken: String? = null): ChunkEntity? { val query = where(realm, roomId) + if (prevToken == null && nextToken == null) return null if (prevToken != null) { query.equalTo(ChunkEntityFields.PREV_TOKEN, prevToken) } @@ -40,7 +41,7 @@ internal fun ChunkEntity.Companion.find(realm: Realm, roomId: String, prevToken: return query.findFirst() } -internal fun ChunkEntity.Companion.findAll(realm: Realm, roomId: String, prevToken: String? = null, nextToken: String? = null): RealmResults<ChunkEntity>? { +internal fun ChunkEntity.Companion.findAll(realm: Realm, roomId: String, prevToken: String? = null, nextToken: String? = null): RealmResults<ChunkEntity> { val query = where(realm, roomId) if (prevToken != null) { query.equalTo(ChunkEntityFields.PREV_TOKEN, prevToken) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/CurrentStateEventEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/CurrentStateEventEntityQueries.kt index 716783f2bab70d0fc06889c4416c2f5153904271..e0dbf2eee82cb7baf4e3c2909093ed015534ee9e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/CurrentStateEventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/CurrentStateEventEntityQueries.kt @@ -23,40 +23,50 @@ import io.realm.kotlin.createObject import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields -internal fun CurrentStateEventEntity.Companion.whereType(realm: Realm, - roomId: String, - type: String): RealmQuery<CurrentStateEventEntity> { +internal fun CurrentStateEventEntity.Companion.whereType( + realm: Realm, + roomId: String, + type: String +): RealmQuery<CurrentStateEventEntity> { return realm.where(CurrentStateEventEntity::class.java) .equalTo(CurrentStateEventEntityFields.ROOM_ID, roomId) .equalTo(CurrentStateEventEntityFields.TYPE, type) } -internal fun CurrentStateEventEntity.Companion.whereStateKey(realm: Realm, - roomId: String, - type: String, - stateKey: String): RealmQuery<CurrentStateEventEntity> { +internal fun CurrentStateEventEntity.Companion.whereStateKey( + realm: Realm, + roomId: String, + type: String, + stateKey: String +): RealmQuery<CurrentStateEventEntity> { return whereType(realm = realm, roomId = roomId, type = type) .equalTo(CurrentStateEventEntityFields.STATE_KEY, stateKey) } -internal fun CurrentStateEventEntity.Companion.getOrNull(realm: Realm, - roomId: String, - stateKey: String, - type: String): CurrentStateEventEntity? { +internal fun CurrentStateEventEntity.Companion.getOrNull( + realm: Realm, + roomId: String, + stateKey: String, + type: String +): CurrentStateEventEntity? { return whereStateKey(realm = realm, roomId = roomId, type = type, stateKey = stateKey).findFirst() } -internal fun CurrentStateEventEntity.Companion.getOrCreate(realm: Realm, - roomId: String, - stateKey: String, - type: String): CurrentStateEventEntity { +internal fun CurrentStateEventEntity.Companion.getOrCreate( + realm: Realm, + roomId: String, + stateKey: String, + type: String +): CurrentStateEventEntity { return getOrNull(realm = realm, roomId = roomId, stateKey = stateKey, type = type) ?: create(realm, roomId, stateKey, type) } -private fun create(realm: Realm, - roomId: String, - stateKey: String, - type: String): CurrentStateEventEntity { +private fun create( + realm: Realm, + roomId: String, + stateKey: String, + type: String +): CurrentStateEventEntity { return realm.createObject<CurrentStateEventEntity>().apply { this.type = type this.roomId = roomId diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventEntityQueries.kt index f7fa1037ba59687e450c5667cf5b2dcc3a714319..0f1c22604410134afe3083dd64ebbeefff36aa4e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventEntityQueries.kt @@ -59,9 +59,10 @@ internal fun EventEntity.Companion.where(realm: Realm, eventIds: List<String>): .`in`(EventEntityFields.EVENT_ID, eventIds.toTypedArray()) } -internal fun EventEntity.Companion.whereType(realm: Realm, - type: String, - roomId: String? = null +internal fun EventEntity.Companion.whereType( + realm: Realm, + type: String, + roomId: String? = null ): RealmQuery<EventEntity> { val query = realm.where<EventEntity>() if (roomId != null) { @@ -70,9 +71,11 @@ internal fun EventEntity.Companion.whereType(realm: Realm, return query.equalTo(EventEntityFields.TYPE, type) } -internal fun EventEntity.Companion.whereTypes(realm: Realm, - typeList: List<String> = emptyList(), - roomId: String? = null): RealmQuery<EventEntity> { +internal fun EventEntity.Companion.whereTypes( + realm: Realm, + typeList: List<String> = emptyList(), + roomId: String? = null +): RealmQuery<EventEntity> { val query = realm.where<EventEntity>() query.`in`(EventEntityFields.TYPE, typeList.toTypedArray()) if (roomId != null) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LiveLocationShareAggregatedSummaryEntityQuery.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LiveLocationShareAggregatedSummaryEntityQuery.kt index 2e2e939fa2003e29e12902e1255eedb591723928..7dfeb6884abf247224c8561a2e6ab6b8a7b2d743 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LiveLocationShareAggregatedSummaryEntityQuery.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/LiveLocationShareAggregatedSummaryEntityQuery.kt @@ -27,10 +27,18 @@ internal fun LiveLocationShareAggregatedSummaryEntity.Companion.where( realm: Realm, roomId: String, eventId: String, +): RealmQuery<LiveLocationShareAggregatedSummaryEntity> { + return LiveLocationShareAggregatedSummaryEntity + .whereRoomId(realm, roomId = roomId) + .equalTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, eventId) +} + +internal fun LiveLocationShareAggregatedSummaryEntity.Companion.whereRoomId( + realm: Realm, + roomId: String ): RealmQuery<LiveLocationShareAggregatedSummaryEntity> { return realm.where<LiveLocationShareAggregatedSummaryEntity>() .equalTo(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, roomId) - .equalTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, eventId) } internal fun LiveLocationShareAggregatedSummaryEntity.Companion.create( @@ -55,3 +63,39 @@ internal fun LiveLocationShareAggregatedSummaryEntity.Companion.getOrCreate( return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).findFirst() ?: LiveLocationShareAggregatedSummaryEntity.create(realm, roomId, eventId) } + +internal fun LiveLocationShareAggregatedSummaryEntity.Companion.get( + realm: Realm, + roomId: String, + eventId: String, +): LiveLocationShareAggregatedSummaryEntity? { + return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).findFirst() +} + +internal fun LiveLocationShareAggregatedSummaryEntity.Companion.findActiveLiveInRoomForUser( + realm: Realm, + roomId: String, + userId: String, + ignoredEventId: String +): List<LiveLocationShareAggregatedSummaryEntity> { + return LiveLocationShareAggregatedSummaryEntity + .whereRoomId(realm, roomId = roomId) + .equalTo(LiveLocationShareAggregatedSummaryEntityFields.USER_ID, userId) + .equalTo(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, true) + .notEqualTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, ignoredEventId) + .findAll() +} + +/** + * A live is considered as running when active and with at least a last known location. + */ +internal fun LiveLocationShareAggregatedSummaryEntity.Companion.findRunningLiveInRoom( + realm: Realm, + roomId: String, +): RealmQuery<LiveLocationShareAggregatedSummaryEntity> { + return LiveLocationShareAggregatedSummaryEntity + .whereRoomId(realm, roomId = roomId) + .equalTo(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, true) + .isNotEmpty(LiveLocationShareAggregatedSummaryEntityFields.USER_ID) + .isNotNull(LiveLocationShareAggregatedSummaryEntityFields.LAST_LOCATION_CONTENT) +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PushersQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PushersQueries.kt index 3cea19a690f8d87e13bafb6a4b67b4c8d3559606..67fd8296d53b622ac6aa5ce44f0e16a41406af00 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PushersQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/PushersQueries.kt @@ -26,8 +26,10 @@ import org.matrix.android.sdk.internal.database.model.PushRulesEntityFields import org.matrix.android.sdk.internal.database.model.PusherEntity import org.matrix.android.sdk.internal.database.model.PusherEntityFields -internal fun PusherEntity.Companion.where(realm: Realm, - pushKey: String? = null): RealmQuery<PusherEntity> { +internal fun PusherEntity.Companion.where( + realm: Realm, + pushKey: String? = null +): RealmQuery<PusherEntity> { return realm.where<PusherEntity>() .apply { if (pushKey != null) { @@ -36,17 +38,21 @@ internal fun PusherEntity.Companion.where(realm: Realm, } } -internal fun PushRulesEntity.Companion.where(realm: Realm, - scope: String, - kind: RuleKind): RealmQuery<PushRulesEntity> { +internal fun PushRulesEntity.Companion.where( + realm: Realm, + scope: String, + kind: RuleKind +): RealmQuery<PushRulesEntity> { return realm.where<PushRulesEntity>() .equalTo(PushRulesEntityFields.SCOPE, scope) .equalTo(PushRulesEntityFields.KIND_STR, kind.name) } -internal fun PushRuleEntity.Companion.where(realm: Realm, - scope: String, - ruleId: String): RealmQuery<PushRuleEntity> { +internal fun PushRuleEntity.Companion.where( + realm: Realm, + scope: String, + ruleId: String +): RealmQuery<PushRuleEntity> { return realm.where<PushRuleEntity>() .equalTo(PushRuleEntityFields.PARENT.SCOPE, scope) .equalTo(PushRuleEntityFields.RULE_ID, ruleId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt index 1a832a29bbbca135aa680e7b7e3d99a925d27266..0b0f01a67de8aff906bc081d8dc7b1f7bc5bec7c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt @@ -24,10 +24,12 @@ import org.matrix.android.sdk.internal.database.model.ReadMarkerEntity import org.matrix.android.sdk.internal.database.model.ReadReceiptEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntity -internal fun isEventRead(realmConfiguration: RealmConfiguration, - userId: String?, - roomId: String?, - eventId: String?): Boolean { +internal fun isEventRead( + realmConfiguration: RealmConfiguration, + userId: String?, + roomId: String?, + eventId: String? +): Boolean { if (userId.isNullOrBlank() || roomId.isNullOrBlank() || eventId.isNullOrBlank()) { return false } @@ -39,12 +41,12 @@ internal fun isEventRead(realmConfiguration: RealmConfiguration, val eventToCheck = TimelineEventEntity.where(realm, roomId, eventId).findFirst() when { // The event doesn't exist locally, let's assume it hasn't been read - eventToCheck == null -> false - eventToCheck.root?.sender == userId -> true + eventToCheck == null -> false + eventToCheck.root?.sender == userId -> true // If new event exists and the latest event is from ourselves we can infer the event is read - latestEventIsFromSelf(realm, roomId, userId) -> true + latestEventIsFromSelf(realm, roomId, userId) -> true eventToCheck.isBeforeLatestReadReceipt(realm, roomId, userId) -> true - else -> false + else -> false } } } @@ -77,9 +79,11 @@ private fun Realm.hasReadReceiptInLatestChunk(latestChunkEntity: ChunkEntity, ro } != null } -internal fun isReadMarkerMoreRecent(realmConfiguration: RealmConfiguration, - roomId: String?, - eventId: String?): Boolean { +internal fun isReadMarkerMoreRecent( + realmConfiguration: RealmConfiguration, + roomId: String?, + eventId: String? +): Boolean { if (roomId.isNullOrBlank() || eventId.isNullOrBlank()) { return false } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomSummaryEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomSummaryEntityQueries.kt index 8993c36a300f1d41b7c510b2eb06d3e315ca9f1e..3c8d61432aa8f56a8331025af0475e7555c744b4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomSummaryEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/RoomSummaryEntityQueries.kt @@ -53,8 +53,10 @@ internal fun RoomSummaryEntity.Companion.getOrNull(realm: Realm, roomId: String) return where(realm, roomId).findFirst() } -internal fun RoomSummaryEntity.Companion.getDirectRooms(realm: Realm, - excludeRoomIds: Set<String>? = null): RealmResults<RoomSummaryEntity> { +internal fun RoomSummaryEntity.Companion.getDirectRooms( + realm: Realm, + excludeRoomIds: Set<String>? = null +): RealmResults<RoomSummaryEntity> { return RoomSummaryEntity.where(realm) .equalTo(RoomSummaryEntityFields.IS_DIRECT, true) .apply { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt index 1654a33806dee20f2bf1f4bfa8c342f3fdd457b5..30010f90fd605213a08687f739b7df2722d65d5b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt @@ -33,39 +33,49 @@ internal fun TimelineEventEntity.Companion.where(realm: Realm): RealmQuery<Timel return realm.where() } -internal fun TimelineEventEntity.Companion.where(realm: Realm, - roomId: String, - eventId: String): RealmQuery<TimelineEventEntity> { +internal fun TimelineEventEntity.Companion.where( + realm: Realm, + roomId: String, + eventId: String +): RealmQuery<TimelineEventEntity> { return where(realm) .equalTo(TimelineEventEntityFields.ROOM_ID, roomId) .equalTo(TimelineEventEntityFields.EVENT_ID, eventId) } -internal fun TimelineEventEntity.Companion.where(realm: Realm, - roomId: String, - eventIds: List<String>): RealmQuery<TimelineEventEntity> { +internal fun TimelineEventEntity.Companion.where( + realm: Realm, + roomId: String, + eventIds: List<String> +): RealmQuery<TimelineEventEntity> { return where(realm) .equalTo(TimelineEventEntityFields.ROOM_ID, roomId) .`in`(TimelineEventEntityFields.EVENT_ID, eventIds.toTypedArray()) } -internal fun TimelineEventEntity.Companion.whereRoomId(realm: Realm, - roomId: String): RealmQuery<TimelineEventEntity> { +internal fun TimelineEventEntity.Companion.whereRoomId( + realm: Realm, + roomId: String +): RealmQuery<TimelineEventEntity> { return where(realm) .equalTo(TimelineEventEntityFields.ROOM_ID, roomId) } -internal fun TimelineEventEntity.Companion.findWithSenderMembershipEvent(realm: Realm, - senderMembershipEventId: String): List<TimelineEventEntity> { +internal fun TimelineEventEntity.Companion.findWithSenderMembershipEvent( + realm: Realm, + senderMembershipEventId: String +): List<TimelineEventEntity> { return where(realm) .equalTo(TimelineEventEntityFields.SENDER_MEMBERSHIP_EVENT_ID, senderMembershipEventId) .findAll() } -internal fun TimelineEventEntity.Companion.latestEvent(realm: Realm, - roomId: String, - includesSending: Boolean, - filters: TimelineEventFilters = TimelineEventFilters()): TimelineEventEntity? { +internal fun TimelineEventEntity.Companion.latestEvent( + realm: Realm, + roomId: String, + includesSending: Boolean, + filters: TimelineEventFilters = TimelineEventFilters() +): TimelineEventEntity? { val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: return null val sendingTimelineEvents = roomEntity.sendingTimelineEvents.where().filterEvents(filters) @@ -129,9 +139,11 @@ internal fun RealmList<TimelineEventEntity>.find(eventId: String): TimelineEvent .findFirst() } -internal fun TimelineEventEntity.Companion.findAllInRoomWithSendStates(realm: Realm, - roomId: String, - sendStates: List<SendState>): RealmResults<TimelineEventEntity> { +internal fun TimelineEventEntity.Companion.findAllInRoomWithSendStates( + realm: Realm, + roomId: String, + sendStates: List<SendState> +): RealmResults<TimelineEventEntity> { return whereRoomId(realm, roomId) .filterSendStates(sendStates) .findAll() @@ -145,8 +157,10 @@ internal fun RealmQuery<TimelineEventEntity>.filterSendStates(sendStates: List<S /** * Find all TimelineEventEntity items where sender is in senderIds collection, excluding state events. */ -internal fun TimelineEventEntity.Companion.findAllFrom(realm: Realm, - senderIds: Collection<String>): RealmResults<TimelineEventEntity> { +internal fun TimelineEventEntity.Companion.findAllFrom( + realm: Realm, + senderIds: Collection<String> +): RealmResults<TimelineEventEntity> { return where(realm) .`in`(TimelineEventEntityFields.ROOT.SENDER, senderIds.toTypedArray()) .isNull(TimelineEventEntityFields.ROOT.STATE_KEY) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt index dbc6aac6b59a329f0685b36880d268217d5a178a..095916643cb8d5e7fc35e54a72d1e65cfa3af103 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt @@ -100,7 +100,9 @@ internal interface MatrixComponent { @Component.Factory interface Factory { - fun create(@BindsInstance context: Context, - @BindsInstance matrixConfiguration: MatrixConfiguration): MatrixComponent + fun create( + @BindsInstance context: Context, + @BindsInstance matrixConfiguration: MatrixConfiguration + ): MatrixComponent } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt index 0cbbe1210d288918441532e24e69eef13a448090..862cf463b2c2ce7e1316c4bda26dea59a09d9c97 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/NetworkModule.kt @@ -62,13 +62,15 @@ internal object NetworkModule { @Provides @JvmStatic @Unauthenticated - fun providesOkHttpClient(matrixConfiguration: MatrixConfiguration, - stethoInterceptor: StethoInterceptor, - timeoutInterceptor: TimeOutInterceptor, - userAgentInterceptor: UserAgentInterceptor, - httpLoggingInterceptor: HttpLoggingInterceptor, - curlLoggingInterceptor: CurlLoggingInterceptor, - apiInterceptor: ApiInterceptor): OkHttpClient { + fun providesOkHttpClient( + matrixConfiguration: MatrixConfiguration, + stethoInterceptor: StethoInterceptor, + timeoutInterceptor: TimeOutInterceptor, + userAgentInterceptor: UserAgentInterceptor, + httpLoggingInterceptor: HttpLoggingInterceptor, + curlLoggingInterceptor: CurlLoggingInterceptor, + apiInterceptor: ApiInterceptor + ): OkHttpClient { val spec = ConnectionSpec.Builder(matrixConfiguration.connectionSpec).build() return OkHttpClient.Builder() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/WorkManagerProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/WorkManagerProvider.kt index c59936af94d314a31dd11708731c0ed2b4038132..ad28286a849a1f1769d4eca703980a76c3d3ac2f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/WorkManagerProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/WorkManagerProvider.kt @@ -59,8 +59,10 @@ internal class WorkManagerProvider @Inject constructor( /** * Create a PeriodicWorkRequestBuilder, with the Matrix SDK tag. */ - inline fun <reified W : ListenableWorker> matrixPeriodicWorkRequestBuilder(repeatInterval: Long, - repeatIntervalTimeUnit: TimeUnit) = + inline fun <reified W : ListenableWorker> matrixPeriodicWorkRequestBuilder( + repeatInterval: Long, + repeatIntervalTimeUnit: TimeUnit + ) = PeriodicWorkRequestBuilder<W>(repeatInterval, repeatIntervalTimeUnit) .addTag(tag) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/federation/FederationModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/federation/FederationModule.kt index a4eef80c58eb0e63f9da9723c04c11b12514df90..bbb29b6255229d4ad529d4ffe75001643493d964 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/federation/FederationModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/federation/FederationModule.kt @@ -34,9 +34,11 @@ internal abstract class FederationModule { companion object { @Provides @JvmStatic - fun providesFederationAPI(@Unauthenticated okHttpClient: Lazy<OkHttpClient>, - sessionParams: SessionParams, - retrofitFactory: RetrofitFactory): FederationAPI { + fun providesFederationAPI( + @Unauthenticated okHttpClient: Lazy<OkHttpClient>, + sessionParams: SessionParams, + retrofitFactory: RetrofitFactory + ): FederationAPI { return retrofitFactory.create(okHttpClient, sessionParams.homeServerUrlBase) .create(FederationAPI::class.java) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt index 0a76fb2eef7172b0e1a83590ab876ab07d685f95..56d9cc21439ca6ab0081b53d02a1f2048f410f76 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt @@ -132,7 +132,7 @@ internal class DefaultLegacySessionImporter @Inject constructor( bytes = it.bytes, hashType = when (it.type) { LegacyFingerprint.HashType.SHA1, - null -> Fingerprint.HashType.SHA1 + null -> Fingerprint.HashType.SHA1 LegacyFingerprint.HashType.SHA256 -> Fingerprint.HashType.SHA256 } ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/HomeServerConnectionConfig.java b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/HomeServerConnectionConfig.java index a1b46f6c09450e7e9f5ec7e6eb981bc84ec01811..b2bb852cd1a842c8c84035a1c36066d45b7bbdbb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/HomeServerConnectionConfig.java +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/riot/HomeServerConnectionConfig.java @@ -612,7 +612,7 @@ public class HomeServerConnectionConfig { * - https://www.ssi.gouv.fr/uploads/2017/02/security-recommendations-for-tls_v1.1.pdf * - https://developer.android.com/reference/javax/net/ssl/SSLEngine * - * @param tlsLimitations true to use Tls limitations + * @param tlsLimitations true to use Tls limitations * @param enableCompatibilityMode set to true for Android < 20 * @return this builder */ @@ -649,7 +649,7 @@ public class HomeServerConnectionConfig { /** * @param proxyHostname Proxy Hostname - * @param proxyPort Proxy Port + * @param proxyPort Proxy Port * @return this builder */ public Builder withProxy(@Nullable String proxyHostname, int proxyPort) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkCallbackStrategy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkCallbackStrategy.kt index 8e18d2d8508c8636b6e7a054432e97d1020a74e4..f75fb01746609097d9c4bb9a6136ae6a95a76282 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkCallbackStrategy.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkCallbackStrategy.kt @@ -31,8 +31,10 @@ internal interface NetworkCallbackStrategy { fun unregister() } -internal class FallbackNetworkCallbackStrategy @Inject constructor(private val context: Context, - private val networkInfoReceiver: NetworkInfoReceiver) : NetworkCallbackStrategy { +internal class FallbackNetworkCallbackStrategy @Inject constructor( + private val context: Context, + private val networkInfoReceiver: NetworkInfoReceiver +) : NetworkCallbackStrategy { @Suppress("DEPRECATION") val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConnectivityChecker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConnectivityChecker.kt index 65bf3fcadf926303670501e01b92b54f07fef1e2..c54227a7866c43c3641ca61e1316b0d8a599dd59 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConnectivityChecker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConnectivityChecker.kt @@ -41,9 +41,11 @@ internal interface NetworkConnectivityChecker { } @SessionScope -internal class DefaultNetworkConnectivityChecker @Inject constructor(private val homeServerPinger: HomeServerPinger, - private val backgroundDetectionObserver: BackgroundDetectionObserver, - private val networkCallbackStrategy: NetworkCallbackStrategy) : +internal class DefaultNetworkConnectivityChecker @Inject constructor( + private val homeServerPinger: HomeServerPinger, + private val backgroundDetectionObserver: BackgroundDetectionObserver, + private val networkCallbackStrategy: NetworkCallbackStrategy +) : NetworkConnectivityChecker { private val hasInternetAccess = AtomicBoolean(true) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ProgressRequestBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ProgressRequestBody.kt index 818d7d6af3a65ae88afb536ccf7f5df84568fb51..6e4d064a0f463a5bab76b2f448e37956bc4f141b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ProgressRequestBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ProgressRequestBody.kt @@ -26,8 +26,10 @@ import okio.buffer import org.matrix.android.sdk.api.extensions.tryOrNull import java.io.IOException -internal class ProgressRequestBody(private val delegate: RequestBody, - private val listener: Listener) : RequestBody() { +internal class ProgressRequestBody( + private val delegate: RequestBody, + private val listener: Listener +) : RequestBody() { private lateinit var countingSink: CountingSink diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt index 695e7525af09580b8db70c40d3552a38a55b0252..fefb7fb5e33676369e1895e4993649d6ab39d259 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/Request.kt @@ -32,6 +32,7 @@ import java.io.IOException * Execute a request from the requestBlock and handle some of the Exception it could generate * Ref: https://github.com/matrix-org/matrix-js-sdk/blob/develop/src/scheduler.js#L138-L175 * + * @param DATA type of data return by the [requestBlock] * @param globalErrorReceiver will be use to notify error such as invalid token error. See [GlobalError] * @param canRetry if set to true, the request will be executed again in case of error, after a delay * @param maxDelayBeforeRetry the max delay to wait before a retry. Note that in the case of a 429, if the provided delay exceeds this value, the error will @@ -39,11 +40,13 @@ import java.io.IOException * @param maxRetriesCount the max number of retries * @param requestBlock a suspend lambda to perform the network request */ -internal suspend inline fun <DATA> executeRequest(globalErrorReceiver: GlobalErrorReceiver?, - canRetry: Boolean = false, - maxDelayBeforeRetry: Long = 32_000L, - maxRetriesCount: Int = 4, - noinline requestBlock: suspend () -> DATA): DATA { +internal suspend inline fun <DATA> executeRequest( + globalErrorReceiver: GlobalErrorReceiver?, + canRetry: Boolean = false, + maxDelayBeforeRetry: Long = 32_000L, + maxRetriesCount: Int = 4, + noinline requestBlock: suspend () -> DATA +): DATA { var currentRetryCount = 0 var currentDelay = 1_000L @@ -53,8 +56,8 @@ internal suspend inline fun <DATA> executeRequest(globalErrorReceiver: GlobalErr } catch (throwable: Throwable) { val exception = when (throwable) { is KotlinNullPointerException -> IllegalStateException("The request returned a null body") - is HttpException -> throwable.toFailure(globalErrorReceiver) - else -> throwable + is HttpException -> throwable.toFailure(globalErrorReceiver) + else -> throwable } // Log some details about the request which has failed. @@ -91,11 +94,11 @@ internal suspend inline fun <DATA> executeRequest(globalErrorReceiver: GlobalErr // Try again (loop) } else { throw when (exception) { - is IOException -> Failure.NetworkConnection(exception) + is IOException -> Failure.NetworkConnection(exception) is Failure.ServerError, is Failure.OtherServerError, is CancellationException -> exception - else -> Failure.Unknown(exception) + else -> Failure.Unknown(exception) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RequestExecutor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RequestExecutor.kt index 71df7c08be9c63607e1d622619bbaf857f70410d..2e8b2bc7717e21944d37a9d16ce35cf065f9402a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RequestExecutor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RequestExecutor.kt @@ -19,19 +19,23 @@ package org.matrix.android.sdk.internal.network import org.matrix.android.sdk.internal.network.executeRequest as internalExecuteRequest internal interface RequestExecutor { - suspend fun <DATA> executeRequest(globalErrorReceiver: GlobalErrorReceiver?, - canRetry: Boolean = false, - maxDelayBeforeRetry: Long = 32_000L, - maxRetriesCount: Int = 4, - requestBlock: suspend () -> DATA): DATA + suspend fun <DATA> executeRequest( + globalErrorReceiver: GlobalErrorReceiver?, + canRetry: Boolean = false, + maxDelayBeforeRetry: Long = 32_000L, + maxRetriesCount: Int = 4, + requestBlock: suspend () -> DATA + ): DATA } internal object DefaultRequestExecutor : RequestExecutor { - override suspend fun <DATA> executeRequest(globalErrorReceiver: GlobalErrorReceiver?, - canRetry: Boolean, - maxDelayBeforeRetry: Long, - maxRetriesCount: Int, - requestBlock: suspend () -> DATA): DATA { + override suspend fun <DATA> executeRequest( + globalErrorReceiver: GlobalErrorReceiver?, + canRetry: Boolean, + maxDelayBeforeRetry: Long, + maxRetriesCount: Int, + requestBlock: suspend () -> DATA + ): DATA { return internalExecuteRequest(globalErrorReceiver, canRetry, maxDelayBeforeRetry, maxRetriesCount, requestBlock) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt index 5268ea851d5f54d6e67562b4fa52ae4ab5fb045e..30f7cdd65b718d7b61655102c2627b5153d41d4d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitExtensions.kt @@ -92,10 +92,10 @@ private fun toFailure(errorBody: ResponseBody?, httpCode: Int, globalErrorReceiv globalErrorReceiver?.handleGlobalError(GlobalError.ConsentNotGivenError(matrixError.consentUri)) } httpCode == HttpURLConnection.HTTP_UNAUTHORIZED && /* 401 */ - matrixError.code == MatrixError.M_UNKNOWN_TOKEN -> { + matrixError.code == MatrixError.M_UNKNOWN_TOKEN -> { globalErrorReceiver?.handleGlobalError(GlobalError.InvalidToken(matrixError.isSoftLogout.orFalse())) } - matrixError.code == MatrixError.ORG_MATRIX_EXPIRED_ACCOUNT -> { + matrixError.code == MatrixError.ORG_MATRIX_EXPIRED_ACCOUNT -> { globalErrorReceiver?.handleGlobalError(GlobalError.ExpiredAccount) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UnitConverterFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UnitConverterFactory.kt index f2571ab73fafaf60d9b5a96a0d92a2600b86b257..8dcff59cbab33c4d2788335f00d2f392c7e57fc2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UnitConverterFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UnitConverterFactory.kt @@ -22,8 +22,10 @@ import retrofit2.Retrofit import java.lang.reflect.Type internal object UnitConverterFactory : Converter.Factory() { - override fun responseBodyConverter(type: Type, annotations: Array<out Annotation>, - retrofit: Retrofit): Converter<ResponseBody, *>? { + override fun responseBodyConverter( + type: Type, annotations: Array<out Annotation>, + retrofit: Retrofit + ): Converter<ResponseBody, *>? { return if (type == Unit::class.java) UnitConverter else null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt index 00e15c283e210169d952511780bbd2482cb4d0c4..28d96dfce7363f2ed58402109467c959557bf862 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt @@ -24,8 +24,10 @@ import timber.log.Timber import javax.inject.Inject @MatrixScope -internal class UserAgentHolder @Inject constructor(private val context: Context, - matrixConfiguration: MatrixConfiguration) { +internal class UserAgentHolder @Inject constructor( + private val context: Context, + matrixConfiguration: MatrixConfiguration +) { var userAgent: String = "" private set diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/ForceToBoolean.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/ForceToBoolean.kt index 628486bb5fab22258b77f105e042b0e4ada7a601..b4925429d01234d2389970eabf7cb78483de3192 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/ForceToBoolean.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/ForceToBoolean.kt @@ -37,9 +37,9 @@ internal class ForceToBooleanJsonAdapter { @ForceToBoolean fun fromJson(reader: JsonReader): Boolean { return when (val token = reader.peek()) { - JsonReader.Token.NUMBER -> reader.nextInt() != 0 + JsonReader.Token.NUMBER -> reader.nextInt() != 0 JsonReader.Token.BOOLEAN -> reader.nextBoolean() - else -> { + else -> { Timber.e("Expecting a boolean or a int but get: $token") reader.skipValue() false diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/RuntimeJsonAdapterFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/RuntimeJsonAdapterFactory.kt index 40d174ee2d5df87d09b22aa8bf6847467ed601f8..7cf3603cc57636da3032a977f497d4082e6eb522 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/RuntimeJsonAdapterFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/RuntimeJsonAdapterFactory.kt @@ -70,11 +70,13 @@ internal class RuntimeJsonAdapterFactory<T>( } @Suppress("UNCHECKED_CAST") - internal class RuntimeJsonAdapter(val labelKey: String, - val labelToAdapter: Map<String, JsonAdapter<Any>>, - val typeToLabel: Map<Type, String>, - val objectJsonAdapter: JsonAdapter<Any>, - val fallbackAdapter: JsonAdapter<Any>) : JsonAdapter<Any?>() { + internal class RuntimeJsonAdapter( + val labelKey: String, + val labelToAdapter: Map<String, JsonAdapter<Any>>, + val typeToLabel: Map<Type, String>, + val objectJsonAdapter: JsonAdapter<Any>, + val fallbackAdapter: JsonAdapter<Any> + ) : JsonAdapter<Any?>() { @Throws(IOException::class) override fun fromJson(reader: JsonReader): Any? { val peekedToken = reader.peek() @@ -119,9 +121,11 @@ internal class RuntimeJsonAdapterFactory<T>( companion object { /** + * @param T the generic type to pass to [RuntimeJsonAdapterFactory] * @param baseType The base type for which this factory will create adapters. Cannot be Object. * @param labelKey The key in the JSON object whose value determines the type to which to map the * JSON object. + * @param fallbackType alternative Type to try in case of the serialization fails */ @CheckReturnValue fun <T> of(baseType: Class<T>, labelKey: String, fallbackType: Class<out T>): RuntimeJsonAdapterFactory<T> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt index 2ef40fe2a3fbb162b8ce3ef1800081cdffd18124..e5659fd76b317229e8579eafb18d2a12d4ce309f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/CertUtil.kt @@ -94,6 +94,7 @@ internal object CertUtil { * Convert the fingerprint to an hexa string. * * @param fingerprint the fingerprint + * @param sep the separator character, default to space * @return the hexa string. */ fun fingerprintToHexString(fingerprint: ByteArray, sep: Char = ' '): String { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManager.kt index ccae5ad14f98c08c84c632f3fa56fbdf16b67d68..1b957c385539ea1ab6dd91074b39e0a9e7a7eaf4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManager.kt @@ -24,15 +24,15 @@ import javax.net.ssl.X509TrustManager /** * Implements a TrustManager that checks Certificates against an explicit list of known * fingerprints. - */ - -/** - * @param fingerprints Not empty array of SHA256 cert fingerprints - * @param defaultTrustManager Optional trust manager to fall back on if cert does not match + * + * @property fingerprints Not empty array of SHA256 cert fingerprints + * @property defaultTrustManager Optional trust manager to fall back on if cert does not match * any of the fingerprints. Can be null. */ -internal class PinnedTrustManager(private val fingerprints: List<Fingerprint>, - private val defaultTrustManager: X509TrustManager?) : X509TrustManager { +internal class PinnedTrustManager( + private val fingerprints: List<Fingerprint>, + private val defaultTrustManager: X509TrustManager? +) : X509TrustManager { @Throws(CertificateException::class) override fun checkClientTrusted(chain: Array<X509Certificate>, s: String) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerApi24.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerApi24.kt index 574f1ef81db6fcfe8cfcc642bbea6ac1ef26d2e3..ef703f3b61ae2f4a5ae40b86f37d30630d0e0e74 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerApi24.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerApi24.kt @@ -28,16 +28,16 @@ import javax.net.ssl.X509ExtendedTrustManager /** * Implements a TrustManager that checks Certificates against an explicit list of known * fingerprints. - */ - -/** - * @param fingerprints An array of SHA256 cert fingerprints - * @param defaultTrustManager Optional trust manager to fall back on if cert does not match + * + * @property fingerprints An array of SHA256 cert fingerprints + * @property defaultTrustManager Optional trust manager to fall back on if cert does not match * any of the fingerprints. Can be null. */ @RequiresApi(Build.VERSION_CODES.N) -internal class PinnedTrustManagerApi24(private val fingerprints: List<Fingerprint>, - private val defaultTrustManager: X509ExtendedTrustManager?) : X509ExtendedTrustManager() { +internal class PinnedTrustManagerApi24( + private val fingerprints: List<Fingerprint>, + private val defaultTrustManager: X509ExtendedTrustManager? +) : X509ExtendedTrustManager() { @Throws(CertificateException::class) override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String, engine: SSLEngine?) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerProvider.kt index f01ee7af24fa04ed6e993fac9a21ae4d0aaa436e..bfdc4e537ee21cd7917946f50a0d502fd3032be8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ssl/PinnedTrustManagerProvider.kt @@ -25,8 +25,10 @@ internal object PinnedTrustManagerProvider { // Set to false to perform some tests private const val USE_DEFAULT_TRUST_MANAGER = true - fun provide(fingerprints: List<Fingerprint>?, - defaultTrustManager: X509TrustManager?): X509TrustManager { + fun provide( + fingerprints: List<Fingerprint>?, + defaultTrustManager: X509TrustManager? + ): X509TrustManager { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && defaultTrustManager is X509ExtendedTrustManager) { PinnedTrustManagerApi24( fingerprints.orEmpty(), diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt index c5ea2d48ad4e517cd8d75cacd2598b46140f6e80..8df048299394713c8bf18af54c24200bcfca5737 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt @@ -24,10 +24,10 @@ import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields internal fun RealmQuery<RoomSummaryEntity>.process(sortOrder: RoomSortOrder): RealmQuery<RoomSummaryEntity> { when (sortOrder) { - RoomSortOrder.NAME -> { + RoomSortOrder.NAME -> { sort(RoomSummaryEntityFields.DISPLAY_NAME, Sort.ASCENDING) } - RoomSortOrder.ACTIVITY -> { + RoomSortOrder.ACTIVITY -> { sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING) } RoomSortOrder.PRIORITY_AND_ACTIVITY -> { @@ -40,7 +40,7 @@ internal fun RealmQuery<RoomSummaryEntity>.process(sortOrder: RoomSortOrder): Re arrayOf(Sort.DESCENDING, Sort.ASCENDING, Sort.DESCENDING) ) } - RoomSortOrder.NONE -> { + RoomSortOrder.NONE -> { } } return this diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt index ba4d05e747a47b246a59ed54d067f04774cb7c7d..b2ab9879df934ed0047d684b9241d925d23a8331 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryStringValueProcessor.kt @@ -31,12 +31,12 @@ internal class QueryStringValueProcessor @Inject constructor( fun <T : RealmObject> RealmQuery<T>.process(field: String, queryStringValue: QueryStringValue): RealmQuery<T> { return when (queryStringValue) { is QueryStringValue.NoCondition -> this - is QueryStringValue.IsNotNull -> isNotNull(field) - is QueryStringValue.IsNull -> isNull(field) - is QueryStringValue.IsEmpty -> isEmpty(field) - is QueryStringValue.IsNotEmpty -> isNotEmpty(field) - is ContentQueryStringValue -> when (queryStringValue) { - is QueryStringValue.Equals -> equalTo(field, queryStringValue.toRealmValue(), queryStringValue.case.toRealmCase()) + is QueryStringValue.IsNotNull -> isNotNull(field) + is QueryStringValue.IsNull -> isNull(field) + is QueryStringValue.IsEmpty -> isEmpty(field) + is QueryStringValue.IsNotEmpty -> isNotEmpty(field) + is ContentQueryStringValue -> when (queryStringValue) { + is QueryStringValue.Equals -> equalTo(field, queryStringValue.toRealmValue(), queryStringValue.case.toRealmCase()) is QueryStringValue.Contains -> contains(field, queryStringValue.toRealmValue(), queryStringValue.case.toRealmCase()) } } @@ -44,7 +44,7 @@ internal class QueryStringValueProcessor @Inject constructor( private fun ContentQueryStringValue.toRealmValue(): String { return when (case) { - QueryStringValue.Case.NORMALIZED -> normalizer.normalize(string) + QueryStringValue.Case.NORMALIZED -> normalizer.normalize(string) QueryStringValue.Case.SENSITIVE, QueryStringValue.Case.INSENSITIVE -> string } @@ -55,6 +55,6 @@ private fun QueryStringValue.Case.toRealmCase(): Case { return when (this) { QueryStringValue.Case.INSENSITIVE -> Case.INSENSITIVE QueryStringValue.Case.SENSITIVE, - QueryStringValue.Case.NORMALIZED -> Case.SENSITIVE + QueryStringValue.Case.NORMALIZED -> Case.SENSITIVE } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GetUrlTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GetUrlTask.kt index d0e2534e7a1bf4f4ea014c693f87c6b6cb95d0f0..87adad9063514b8f742fcce8019005642d42de71 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GetUrlTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/GetUrlTask.kt @@ -42,8 +42,8 @@ internal class DefaultGetUrlTask @Inject constructor( override suspend fun execute(params: GetUrlTask.Params): String { return when (params.cacheStrategy) { - CacheStrategy.NoCache -> doRequest(params.url) - is CacheStrategy.TtlCache -> doRequestWithCache( + CacheStrategy.NoCache -> doRequest(params.url) + is CacheStrategy.TtlCache -> doRequestWithCache( params.url, params.cacheStrategy.validityDurationInMillis, params.cacheStrategy.strict diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt index a8309766710007e1101b488f97be61035bcfce8c..4b643f1fef7ecd35dcbcc539a5a537c1b2b2257a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/raw/RawModule.kt @@ -51,8 +51,10 @@ internal abstract class RawModule { @Provides @GlobalDatabase @MatrixScope - fun providesRealmConfiguration(realmKeysUtils: RealmKeysUtils, - globalRealmMigration: GlobalRealmMigration): RealmConfiguration { + fun providesRealmConfiguration( + realmKeysUtils: RealmKeysUtils, + globalRealmMigration: GlobalRealmMigration + ): RealmConfiguration { return RealmConfiguration.Builder() .apply { realmKeysUtils.configureEncryption(this, DB_ALIAS) @@ -67,8 +69,10 @@ internal abstract class RawModule { @Provides @JvmStatic - fun providesRawAPI(@Unauthenticated okHttpClient: Lazy<OkHttpClient>, - retrofitFactory: RetrofitFactory): RawAPI { + fun providesRawAPI( + @Unauthenticated okHttpClient: Lazy<OkHttpClient>, + retrofitFactory: RetrofitFactory + ): RawAPI { return retrofitFactory.create(okHttpClient, "https://example.org").create(RawAPI::class.java) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt index 760aa410817389bce1a762c2917669ebbccc3026..bbf260a3f135c002f187bb73ea951a9df705fd96 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt @@ -80,10 +80,12 @@ internal class DefaultFileService @Inject constructor( * Download file in the cache folder, and eventually decrypt it. * TODO looks like files are copied 3 times */ - override suspend fun downloadFile(fileName: String, - mimeType: String?, - url: String?, - elementToDecrypt: ElementToDecrypt?): File { + override suspend fun downloadFile( + fileName: String, + mimeType: String?, + url: String?, + elementToDecrypt: ElementToDecrypt? + ): File { url ?: throw IllegalArgumentException("url is null") Timber.v("## FileService downloadFile $url") @@ -125,7 +127,7 @@ internal class DefaultFileService @Inject constructor( val resolvedUrl = contentUrlResolver.resolveForDownload(url, elementToDecrypt) ?: throw IllegalArgumentException("url is null") val request = when (resolvedUrl) { - is ContentUrlResolver.ResolvedMethod.GET -> { + is ContentUrlResolver.ResolvedMethod.GET -> { Request.Builder() .url(resolvedUrl.url) .header(DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER, url) @@ -218,11 +220,13 @@ internal class DefaultFileService @Inject constructor( return result.getOrThrow() } - fun storeDataFor(mxcUrl: String, - filename: String?, - mimeType: String?, - originalFile: File, - encryptedFile: File?) { + fun storeDataFor( + mxcUrl: String, + filename: String?, + mimeType: String?, + originalFile: File, + encryptedFile: File? + ) { val files = getFiles(mxcUrl, filename, mimeType, encryptedFile != null) if (encryptedFile != null) { // We switch the two files here, original file it the decrypted file @@ -256,10 +260,12 @@ internal class DefaultFileService @Inject constructor( } } - override fun isFileInCache(mxcUrl: String?, - fileName: String, - mimeType: String?, - elementToDecrypt: ElementToDecrypt?): Boolean { + override fun isFileInCache( + mxcUrl: String?, + fileName: String, + mimeType: String?, + elementToDecrypt: ElementToDecrypt? + ): Boolean { return fileState(mxcUrl, fileName, mimeType, elementToDecrypt) is FileService.FileState.InCache } @@ -272,10 +278,12 @@ internal class DefaultFileService @Inject constructor( fun getClearFile(): File = decryptedFile ?: file } - private fun getFiles(mxcUrl: String, - fileName: String?, - mimeType: String?, - isEncrypted: Boolean): CachedFiles { + private fun getFiles( + mxcUrl: String, + fileName: String?, + mimeType: String?, + isEncrypted: Boolean + ): CachedFiles { val hashFolder = mxcUrl.md5() val safeFileName = safeFileName(fileName, mimeType) return if (isEncrypted) { @@ -293,10 +301,12 @@ internal class DefaultFileService @Inject constructor( } } - override fun fileState(mxcUrl: String?, - fileName: String, - mimeType: String?, - elementToDecrypt: ElementToDecrypt?): FileService.FileState { + override fun fileState( + mxcUrl: String?, + fileName: String, + mimeType: String?, + elementToDecrypt: ElementToDecrypt? + ): FileService.FileState { mxcUrl ?: return FileService.FileState.Unknown val files = getFiles(mxcUrl, fileName, mimeType, elementToDecrypt != null) if (files.file.exists()) { @@ -314,10 +324,12 @@ internal class DefaultFileService @Inject constructor( * Use this URI and pass it to intent using flag Intent.FLAG_GRANT_READ_URI_PERMISSION * (if not other app won't be able to access it). */ - override fun getTemporarySharableURI(mxcUrl: String?, - fileName: String, - mimeType: String?, - elementToDecrypt: ElementToDecrypt?): Uri? { + override fun getTemporarySharableURI( + mxcUrl: String?, + fileName: String, + mimeType: String?, + elementToDecrypt: ElementToDecrypt? + ): Uri? { mxcUrl ?: return null // this string could be extracted no? val authority = "${context.packageName}.mx-sdk.fileprovider" diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index 5f77cfb23a702ec54ab3cdb615897e5b899eb4fa..32269c9afddbdbe0bf751e38c1743b9b5da7eedf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -44,7 +44,6 @@ import org.matrix.android.sdk.api.session.file.FileService import org.matrix.android.sdk.api.session.group.GroupService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService import org.matrix.android.sdk.api.session.identity.IdentityService -import org.matrix.android.sdk.api.session.initsync.SyncStatusService import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService import org.matrix.android.sdk.api.session.media.MediaService import org.matrix.android.sdk.api.session.openid.OpenIdService @@ -61,6 +60,7 @@ import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageServi import org.matrix.android.sdk.api.session.signout.SignOutService import org.matrix.android.sdk.api.session.space.SpaceService import org.matrix.android.sdk.api.session.sync.FilterService +import org.matrix.android.sdk.api.session.sync.SyncService import org.matrix.android.sdk.api.session.terms.TermsService import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService import org.matrix.android.sdk.api.session.typing.TypingUsersTracker @@ -76,13 +76,8 @@ import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate import org.matrix.android.sdk.internal.di.WorkManagerProvider import org.matrix.android.sdk.internal.network.GlobalErrorHandler -import org.matrix.android.sdk.internal.session.sync.SyncTokenStore -import org.matrix.android.sdk.internal.session.sync.job.SyncThread -import org.matrix.android.sdk.internal.session.sync.job.SyncWorker import org.matrix.android.sdk.internal.util.createUIHandler -import timber.log.Timber import javax.inject.Inject -import javax.inject.Provider @SessionScope internal class DefaultSession @Inject constructor( @@ -112,16 +107,14 @@ internal class DefaultSession @Inject constructor( private val permalinkService: Lazy<PermalinkService>, private val secureStorageService: Lazy<SecureStorageService>, private val profileService: Lazy<ProfileService>, + private val syncService: Lazy<SyncService>, private val mediaService: Lazy<MediaService>, private val widgetService: Lazy<WidgetService>, - private val syncThreadProvider: Provider<SyncThread>, private val contentUrlResolver: ContentUrlResolver, - private val syncTokenStore: SyncTokenStore, private val sessionParamsStore: SessionParamsStore, private val contentUploadProgressTracker: ContentUploadStateTracker, private val typingUsersTracker: TypingUsersTracker, private val contentDownloadStateTracker: ContentDownloadStateTracker, - private val syncStatusService: Lazy<SyncStatusService>, private val homeServerCapabilitiesService: Lazy<HomeServerCapabilitiesService>, private val accountDataService: Lazy<SessionAccountDataService>, private val sharedSecretStorageService: Lazy<SharedSecretStorageService>, @@ -138,14 +131,11 @@ internal class DefaultSession @Inject constructor( private val toDeviceService: Lazy<ToDeviceService>, private val eventStreamService: Lazy<EventStreamService>, @UnauthenticatedWithCertificate - private val unauthenticatedWithCertificateOkHttpClient: Lazy<OkHttpClient> + private val unauthenticatedWithCertificateOkHttpClient: Lazy<OkHttpClient>, + private val sessionState: SessionState, ) : Session, GlobalErrorHandler.Listener { - private var isOpen = false - - private var syncThread: SyncThread? = null - private val uiHandler = createUIHandler() override val isOpenable: Boolean @@ -153,8 +143,7 @@ internal class DefaultSession @Inject constructor( @MainThread override fun open() { - assert(!isOpen) - isOpen = true + sessionState.setIsOpen(true) globalErrorHandler.listener = this cryptoService.get().ensureDevice() uiHandler.post { @@ -167,40 +156,9 @@ internal class DefaultSession @Inject constructor( } } - override fun requireBackgroundSync() { - SyncWorker.requireBackgroundSync(workManagerProvider, sessionId) - } - - override fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long) { - SyncWorker.automaticallyBackgroundSync(workManagerProvider, sessionId, timeOutInSeconds, repeatDelayInSeconds) - } - - override fun stopAnyBackgroundSync() { - SyncWorker.stopAnyBackgroundSync(workManagerProvider) - } - - override fun startSync(fromForeground: Boolean) { - Timber.i("Starting sync thread") - assert(isOpen) - val localSyncThread = getSyncThread() - localSyncThread.setInitialForeground(fromForeground) - if (!localSyncThread.isAlive) { - localSyncThread.start() - } else { - localSyncThread.restart() - Timber.w("Attempt to start an already started thread") - } - } - - override fun stopSync() { - assert(isOpen) - syncThread?.kill() - syncThread = null - } - override fun close() { - assert(isOpen) - stopSync() + assert(sessionState.isOpen) + syncService.get().stopSync() // timelineEventDecryptor.destroy() uiHandler.post { lifecycleObservers.forEach { it.onSessionStopped(this) } @@ -210,28 +168,12 @@ internal class DefaultSession @Inject constructor( } cryptoService.get().close() globalErrorHandler.listener = null - isOpen = false - } - - override fun getSyncStateLive() = getSyncThread().liveState() - - override fun syncFlow() = getSyncThread().syncFlow() - - override fun getSyncState() = getSyncThread().currentState() - - override fun hasAlreadySynced(): Boolean { - return syncTokenStore.getLastToken() != null - } - - private fun getSyncThread(): SyncThread { - return syncThread ?: syncThreadProvider.get().also { - syncThread = it - } + sessionState.setIsOpen(false) } override suspend fun clearCache() { - stopSync() - stopAnyBackgroundSync() + syncService.get().stopSync() + syncService.get().stopAnyBackgroundSync() uiHandler.post { lifecycleObservers.forEach { it.onClearCache(this) @@ -271,7 +213,7 @@ internal class DefaultSession @Inject constructor( override fun pushersService(): PushersService = pushersService.get() override fun eventService(): EventService = eventService.get() override fun termsService(): TermsService = termsService.get() - override fun syncStatusService(): SyncStatusService = syncStatusService.get() + override fun syncService(): SyncService = syncService.get() override fun secureStorageService(): SecureStorageService = secureStorageService.get() override fun profileService(): ProfileService = profileService.get() override fun presenceService(): PresenceService = presenceService.get() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt index 050480e6c955d58a4d4e01ed749c82cd1ba30ed8..f01451b6887e4b1b5e85b14ed5be44ada7664676 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt @@ -46,6 +46,7 @@ import org.matrix.android.sdk.internal.session.profile.ProfileModule import org.matrix.android.sdk.internal.session.pushers.AddPusherWorker import org.matrix.android.sdk.internal.session.pushers.PushersModule import org.matrix.android.sdk.internal.session.room.RoomModule +import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.DeactivateLiveLocationShareWorker import org.matrix.android.sdk.internal.session.room.send.MultipleEventSendingDispatcherWorker import org.matrix.android.sdk.internal.session.room.send.RedactEventWorker import org.matrix.android.sdk.internal.session.room.send.SendEventWorker @@ -131,10 +132,13 @@ internal interface SessionComponent { fun inject(worker: UpdateTrustWorker) + fun inject(worker: DeactivateLiveLocationShareWorker) + @Component.Factory interface Factory { fun create( matrixComponent: MatrixComponent, - @BindsInstance sessionParams: SessionParams): SessionComponent + @BindsInstance sessionParams: SessionParams + ): SessionComponent } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index 7ceb89e892c24c8a27649b9985746f59633c0fba..2c2317de0d0ed7a6bd06526c109e1a9626d216b4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -39,7 +39,6 @@ import org.matrix.android.sdk.api.session.ToDeviceService import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService import org.matrix.android.sdk.api.session.events.EventService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService -import org.matrix.android.sdk.api.session.initsync.SyncStatusService import org.matrix.android.sdk.api.session.openid.OpenIdService import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.securestorage.SecureStorageService @@ -82,13 +81,12 @@ import org.matrix.android.sdk.internal.session.download.DownloadProgressIntercep import org.matrix.android.sdk.internal.session.events.DefaultEventService import org.matrix.android.sdk.internal.session.homeserver.DefaultHomeServerCapabilitiesService import org.matrix.android.sdk.internal.session.identity.DefaultIdentityService -import org.matrix.android.sdk.internal.session.initsync.DefaultSyncStatusService import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManager import org.matrix.android.sdk.internal.session.openid.DefaultOpenIdService import org.matrix.android.sdk.internal.session.permalinks.DefaultPermalinkService import org.matrix.android.sdk.internal.session.room.EventRelationsAggregationProcessor -import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.DefaultLiveLocationAggregationProcessor -import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.LiveLocationAggregationProcessor +import org.matrix.android.sdk.internal.session.room.aggregation.poll.DefaultPollAggregationProcessor +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollAggregationProcessor import org.matrix.android.sdk.internal.session.room.create.RoomCreateEventProcessor import org.matrix.android.sdk.internal.session.room.prune.RedactionEventProcessor import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor @@ -166,9 +164,11 @@ internal abstract class SessionModule { @Provides @SessionFilesDirectory @SessionScope - fun providesFilesDir(@UserMd5 userMd5: String, - @SessionId sessionId: String, - context: Context): File { + fun providesFilesDir( + @UserMd5 userMd5: String, + @SessionId sessionId: String, + context: Context + ): File { // Temporary code for migration val old = File(context.filesDir, userMd5) if (old.exists()) { @@ -181,8 +181,10 @@ internal abstract class SessionModule { @JvmStatic @Provides @SessionDownloadsDirectory - fun providesDownloadsCacheDir(@SessionId sessionId: String, - @CacheDirectory cacheFile: File): File { + fun providesDownloadsCacheDir( + @SessionId sessionId: String, + @CacheDirectory cacheFile: File + ): File { return File(cacheFile, "downloads/$sessionId") } @@ -208,8 +210,10 @@ internal abstract class SessionModule { @Provides @SessionScope @UnauthenticatedWithCertificate - fun providesOkHttpClientWithCertificate(@Unauthenticated okHttpClient: OkHttpClient, - homeServerConnectionConfig: HomeServerConnectionConfig): OkHttpClient { + fun providesOkHttpClientWithCertificate( + @Unauthenticated okHttpClient: OkHttpClient, + homeServerConnectionConfig: HomeServerConnectionConfig + ): OkHttpClient { return okHttpClient .newBuilder() .addSocketFactory(homeServerConnectionConfig) @@ -220,10 +224,12 @@ internal abstract class SessionModule { @Provides @SessionScope @Authenticated - fun providesOkHttpClient(@UnauthenticatedWithCertificate okHttpClient: OkHttpClient, - @Authenticated accessTokenProvider: AccessTokenProvider, - @SessionId sessionId: String, - @MockHttpInterceptor testInterceptor: TestInterceptor?): OkHttpClient { + fun providesOkHttpClient( + @UnauthenticatedWithCertificate okHttpClient: OkHttpClient, + @Authenticated accessTokenProvider: AccessTokenProvider, + @SessionId sessionId: String, + @MockHttpInterceptor testInterceptor: TestInterceptor? + ): OkHttpClient { return okHttpClient .newBuilder() .addAccessTokenInterceptor(accessTokenProvider) @@ -240,8 +246,10 @@ internal abstract class SessionModule { @Provides @SessionScope @UnauthenticatedWithCertificateWithProgress - fun providesProgressOkHttpClient(@UnauthenticatedWithCertificate okHttpClient: OkHttpClient, - downloadProgressInterceptor: DownloadProgressInterceptor): OkHttpClient { + fun providesProgressOkHttpClient( + @UnauthenticatedWithCertificate okHttpClient: OkHttpClient, + downloadProgressInterceptor: DownloadProgressInterceptor + ): OkHttpClient { return okHttpClient.newBuilder() .apply { // Remove the previous CurlLoggingInterceptor, to add it after the accessTokenInterceptor @@ -260,9 +268,11 @@ internal abstract class SessionModule { @JvmStatic @Provides @SessionScope - fun providesRetrofit(@Authenticated okHttpClient: Lazy<OkHttpClient>, - sessionParams: SessionParams, - retrofitFactory: RetrofitFactory): Retrofit { + fun providesRetrofit( + @Authenticated okHttpClient: Lazy<OkHttpClient>, + sessionParams: SessionParams, + retrofitFactory: RetrofitFactory + ): Retrofit { return retrofitFactory .create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUriBase.toString()) } @@ -270,8 +280,9 @@ internal abstract class SessionModule { @JvmStatic @Provides @SessionScope - fun providesNetworkCallbackStrategy(fallbackNetworkCallbackStrategy: Provider<FallbackNetworkCallbackStrategy>, - preferredNetworkCallbackStrategy: Provider<PreferredNetworkCallbackStrategy> + fun providesNetworkCallbackStrategy( + fallbackNetworkCallbackStrategy: Provider<FallbackNetworkCallbackStrategy>, + preferredNetworkCallbackStrategy: Provider<PreferredNetworkCallbackStrategy> ): NetworkCallbackStrategy { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { preferredNetworkCallbackStrategy.get() @@ -349,9 +360,6 @@ internal abstract class SessionModule { @IntoSet abstract fun bindEventSenderProcessorAsSessionLifecycleObserver(processor: EventSenderProcessorCoroutine): SessionLifecycleObserver - @Binds - abstract fun bindSyncStatusService(service: DefaultSyncStatusService): SyncStatusService - @Binds abstract fun bindSecureStorageService(service: DefaultSecureStorageService): SecureStorageService @@ -389,5 +397,5 @@ internal abstract class SessionModule { abstract fun bindEventSenderProcessor(processor: EventSenderProcessorCoroutine): EventSenderProcessor @Binds - abstract fun bindLiveLocationAggregationProcessor(processor: DefaultLiveLocationAggregationProcessor): LiveLocationAggregationProcessor + abstract fun bindPollAggregationProcessor(processor: DefaultPollAggregationProcessor): PollAggregationProcessor } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionState.kt new file mode 100644 index 0000000000000000000000000000000000000000..b109a9aa60305e7b3bbcd30506af32c27f0eb662 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionState.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session + +import javax.inject.Inject + +@SessionScope +internal class SessionState @Inject constructor() { + var isOpen = false + private set + + /** + * Set the new state. Throw if already in the new state. + */ + fun setIsOpen(newState: Boolean) { + assert(newState != isOpen) + isOpen = newState + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt index 9f3f1f649eea158658c51d6fa3f2e74cb60a2553..5f4d3d5fbce45f82b6aad115b73b520951431267 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DeactivateAccountTask.kt @@ -60,10 +60,10 @@ internal class DefaultDeactivateAccountTask @Inject constructor( execute(params.copy(userAuthParam = authUpdate)) } )) { - UiaResult.SUCCESS -> { + UiaResult.SUCCESS -> { false } - UiaResult.FAILURE -> { + UiaResult.FAILURE -> { Timber.d("## UIA: propagate failure") throw throwable } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt index dc77d7bffb07b5fcf85120e35e90df3613f4628d..bb830a5e419a1bc42e906c0b0bbd9c4442d481b0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/account/DefaultAccountService.kt @@ -20,8 +20,10 @@ import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.session.account.AccountService import javax.inject.Inject -internal class DefaultAccountService @Inject constructor(private val changePasswordTask: ChangePasswordTask, - private val deactivateAccountTask: DeactivateAccountTask) : AccountService { +internal class DefaultAccountService @Inject constructor( + private val changePasswordTask: ChangePasswordTask, + private val deactivateAccountTask: DeactivateAccountTask +) : AccountService { override suspend fun changePassword(password: String, newPassword: String) { changePasswordTask.execute(ChangePasswordTask.Params(password, newPassword)) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt index c4f711a9e6fb33966a55e93bfde2b4c59b4a80eb..48a9dfd3dafd6af055ba2fe5aab06535c485cfed 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt @@ -63,25 +63,25 @@ internal class CallSignalingHandler @Inject constructor( fun onCallEvent(event: Event) { when (event.getClearType()) { - EventType.CALL_ANSWER -> { + EventType.CALL_ANSWER -> { handleCallAnswerEvent(event) } - EventType.CALL_INVITE -> { + EventType.CALL_INVITE -> { handleCallInviteEvent(event) } - EventType.CALL_HANGUP -> { + EventType.CALL_HANGUP -> { handleCallHangupEvent(event) } - EventType.CALL_REJECT -> { + EventType.CALL_REJECT -> { handleCallRejectEvent(event) } - EventType.CALL_CANDIDATES -> { + EventType.CALL_CANDIDATES -> { handleCallCandidatesEvent(event) } - EventType.CALL_SELECT_ANSWER -> { + EventType.CALL_SELECT_ANSWER -> { handleCallSelectAnswerEvent(event) } - EventType.CALL_NEGOTIATE -> { + EventType.CALL_NEGOTIATE -> { handleCallNegotiateEvent(event) } EventType.CALL_ASSERTED_IDENTITY, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/MxCallFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/MxCallFactory.kt index 9ec892b65db549942596b9b0d6e3f5068d0609e4..5b4100f276aae6ad7068bb1b24000b6dcc03d5da 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/MxCallFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/MxCallFactory.kt @@ -79,10 +79,12 @@ internal class MxCallFactory @Inject constructor( } } - fun updateOutgoingCallWithOpponentData(call: MxCall, - userId: String, - content: CallSignalingContent, - callCapabilities: CallCapabilities?) { + fun updateOutgoingCallWithOpponentData( + call: MxCall, + userId: String, + content: CallSignalingContent, + callCapabilities: CallCapabilities? + ) { (call as? MxCallImpl)?.updateOpponentData(userId, content, callCapabilities) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt index 796e83311f89bde906a7c58eea9ca0112f1445cd..13a77e55e18e3cd3519a0e2237bbd282be1dac1b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt @@ -220,10 +220,12 @@ internal class MxCallImpl( .also { eventSenderProcessor.postEvent(it) } } - override suspend fun transfer(targetUserId: String, - targetRoomId: String?, - createCallId: String?, - awaitCallId: String?) { + override suspend fun transfer( + targetUserId: String, + targetRoomId: String?, + createCallId: String?, + awaitCallId: String? + ) { val profileInfoParams = GetProfileInfoTask.Params(targetUserId) val profileInfo = try { getProfileInfoTask.execute(profileInfoParams) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt index 5d7742448234d467904f33273489d5da515623e3..ad2b9d0905e9f8944466e5f3a01f873871be19a0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUrlResolver.kt @@ -80,9 +80,11 @@ internal class DefaultContentUrlResolver @Inject constructor( } } - private fun resolve(contentUrl: String, - toThumbnail: Boolean, - params: String = ""): String { + private fun resolve( + contentUrl: String, + toThumbnail: Boolean, + params: String = "" + ): String { var serverAndMediaId = contentUrl.removeMxcPrefix() val apiPath = if (scannerService.isScannerEnabled()) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt index f96a019fe22aabfeaeae39b8b9401d44d46152e9..c023646c7fa6e57f0b0f11f97dddb6b4cc7f6af9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt @@ -62,10 +62,12 @@ internal class FileUploader @Inject constructor( private val uploadUrl = contentUrlResolver.uploadUrl private val responseAdapter = moshi.adapter(ContentUploadResponse::class.java) - suspend fun uploadFile(file: File, - filename: String?, - mimeType: String?, - progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse { + suspend fun uploadFile( + file: File, + filename: String?, + mimeType: String?, + progressListener: ProgressRequestBody.Listener? = null + ): ContentUploadResponse { // Check size limit val maxUploadFileSize = homeServerCapabilitiesService.getHomeServerCapabilities().maxUploadFileSize @@ -99,18 +101,22 @@ internal class FileUploader @Inject constructor( return upload(uploadBody, filename, progressListener) } - suspend fun uploadByteArray(byteArray: ByteArray, - filename: String?, - mimeType: String?, - progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse { + suspend fun uploadByteArray( + byteArray: ByteArray, + filename: String?, + mimeType: String?, + progressListener: ProgressRequestBody.Listener? = null + ): ContentUploadResponse { val uploadBody = byteArray.toRequestBody(mimeType?.toMediaTypeOrNull()) return upload(uploadBody, filename, progressListener) } - suspend fun uploadFromUri(uri: Uri, - filename: String?, - mimeType: String?, - progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse { + suspend fun uploadFromUri( + uri: Uri, + filename: String?, + mimeType: String?, + progressListener: ProgressRequestBody.Listener? = null + ): ContentUploadResponse { val workingFile = context.copyUriToTempFile(uri) return uploadFile(workingFile, filename, mimeType, progressListener).also { tryOrNull { workingFile.delete() } @@ -128,9 +134,11 @@ internal class FileUploader @Inject constructor( } } - private suspend fun upload(uploadBody: RequestBody, - filename: String?, - progressListener: ProgressRequestBody.Listener?): ContentUploadResponse { + private suspend fun upload( + uploadBody: RequestBody, + filename: String?, + progressListener: ProgressRequestBody.Listener? + ): ContentUploadResponse { val urlBuilder = uploadUrl.toHttpUrlOrNull()?.newBuilder() ?: throw RuntimeException() val httpUrl = urlBuilder diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt index c5aa6cd5e717bc1864d32cbaf1f463161ccb8545..bc04cac35ab5c4d7c809e6705d231eb7493a7ee5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt @@ -35,7 +35,8 @@ internal class ImageCompressor @Inject constructor( imageFile: File, desiredWidth: Int, desiredHeight: Int, - desiredQuality: Int = 80): File { + desiredQuality: Int = 80 + ): File { return withContext(coroutineDispatchers.io) { val compressedBitmap = BitmapFactory.Options().run { inJustDecodeBounds = true @@ -68,20 +69,20 @@ internal class ImageCompressor @Inject constructor( val orientation = exifInfo.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL) val matrix = Matrix() when (orientation) { - ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270f) - ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180f) - ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90f) + ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270f) + ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180f) + ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90f) ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> matrix.preScale(-1f, 1f) - ExifInterface.ORIENTATION_FLIP_VERTICAL -> matrix.preScale(1f, -1f) - ExifInterface.ORIENTATION_TRANSPOSE -> { + ExifInterface.ORIENTATION_FLIP_VERTICAL -> matrix.preScale(1f, -1f) + ExifInterface.ORIENTATION_TRANSPOSE -> { matrix.preRotate(-90f) matrix.preScale(-1f, 1f) } - ExifInterface.ORIENTATION_TRANSVERSE -> { + ExifInterface.ORIENTATION_TRANSVERSE -> { matrix.preRotate(90f) matrix.preScale(-1f, 1f) } - else -> return bitmap + else -> return bitmap } return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt index 5a00c4b5b477f53bbeffef003063145bc8ca455b..1e62b5d7f5b2e63622b4c4aa437cd02617326140 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt @@ -192,7 +192,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter }) .let { videoCompressionResult -> when (videoCompressionResult) { - is VideoCompressionResult.Success -> { + is VideoCompressionResult.Success -> { val compressedFile = videoCompressionResult.compressedFile var compressedWidth: Int? = null var compressedHeight: Int? = null @@ -375,12 +375,14 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter ) } - private suspend fun handleSuccess(params: Params, - attachmentUrl: String, - encryptedFileInfo: EncryptedFileInfo?, - thumbnailUrl: String?, - thumbnailEncryptedFileInfo: EncryptedFileInfo?, - newAttachmentAttributes: NewAttachmentAttributes): Result { + private suspend fun handleSuccess( + params: Params, + attachmentUrl: String, + encryptedFileInfo: EncryptedFileInfo?, + thumbnailUrl: String?, + thumbnailEncryptedFileInfo: EncryptedFileInfo?, + newAttachmentAttributes: NewAttachmentAttributes + ): Result { notifyTracker(params) { contentUploadStateTracker.setSuccess(it) } params.localEchoIds.forEach { updateEvent(it.eventId, attachmentUrl, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo, newAttachmentAttributes) @@ -396,20 +398,22 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter } } - private suspend fun updateEvent(eventId: String, - url: String, - encryptedFileInfo: EncryptedFileInfo?, - thumbnailUrl: String? = null, - thumbnailEncryptedFileInfo: EncryptedFileInfo?, - newAttachmentAttributes: NewAttachmentAttributes) { + private suspend fun updateEvent( + eventId: String, + url: String, + encryptedFileInfo: EncryptedFileInfo?, + thumbnailUrl: String? = null, + thumbnailEncryptedFileInfo: EncryptedFileInfo?, + newAttachmentAttributes: NewAttachmentAttributes + ) { localEchoRepository.updateEcho(eventId) { _, event -> val messageContent: MessageContent? = event.asDomain().content.toModel() val updatedContent = when (messageContent) { is MessageImageContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes) is MessageVideoContent -> messageContent.update(url, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo, newAttachmentAttributes) - is MessageFileContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes.newFileSize) + is MessageFileContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes.newFileSize) is MessageAudioContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes.newFileSize) - else -> messageContent + else -> messageContent } event.content = ContentMapper.map(updatedContent.toContent()) } @@ -419,9 +423,11 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter params.localEchoIds.forEach { function.invoke(it.eventId) } } - private fun MessageImageContent.update(url: String, - encryptedFileInfo: EncryptedFileInfo?, - newAttachmentAttributes: NewAttachmentAttributes?): MessageImageContent { + private fun MessageImageContent.update( + url: String, + encryptedFileInfo: EncryptedFileInfo?, + newAttachmentAttributes: NewAttachmentAttributes? + ): MessageImageContent { return copy( url = if (encryptedFileInfo == null) url else null, encryptedFileInfo = encryptedFileInfo?.copy(url = url), @@ -433,11 +439,13 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter ) } - private fun MessageVideoContent.update(url: String, - encryptedFileInfo: EncryptedFileInfo?, - thumbnailUrl: String?, - thumbnailEncryptedFileInfo: EncryptedFileInfo?, - newAttachmentAttributes: NewAttachmentAttributes?): MessageVideoContent { + private fun MessageVideoContent.update( + url: String, + encryptedFileInfo: EncryptedFileInfo?, + thumbnailUrl: String?, + thumbnailEncryptedFileInfo: EncryptedFileInfo?, + newAttachmentAttributes: NewAttachmentAttributes? + ): MessageVideoContent { return copy( url = if (encryptedFileInfo == null) url else null, encryptedFileInfo = encryptedFileInfo?.copy(url = url), @@ -451,9 +459,11 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter ) } - private fun MessageFileContent.update(url: String, - encryptedFileInfo: EncryptedFileInfo?, - size: Long): MessageFileContent { + private fun MessageFileContent.update( + url: String, + encryptedFileInfo: EncryptedFileInfo?, + size: Long + ): MessageFileContent { return copy( url = if (encryptedFileInfo == null) url else null, encryptedFileInfo = encryptedFileInfo?.copy(url = url), @@ -461,9 +471,11 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter ) } - private fun MessageAudioContent.update(url: String, - encryptedFileInfo: EncryptedFileInfo?, - size: Long): MessageAudioContent { + private fun MessageAudioContent.update( + url: String, + encryptedFileInfo: EncryptedFileInfo?, + size: Long + ): MessageAudioContent { return copy( url = if (encryptedFileInfo == null) url else null, encryptedFileInfo = encryptedFileInfo?.copy(url = url), diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt index a43f8abf3347b7b5286945b7057632e0ee96c0ec..5c00927e2356f8c112bc88219a9609ae98d6d09f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/VideoCompressor.kt @@ -32,8 +32,10 @@ internal class VideoCompressor @Inject constructor( private val temporaryFileCreator: TemporaryFileCreator ) { - suspend fun compress(videoFile: File, - progressListener: ProgressListener?): VideoCompressionResult { + suspend fun compress( + videoFile: File, + progressListener: ProgressListener? + ): VideoCompressionResult { val destinationFile = temporaryFileCreator.create() val job = Job() @@ -111,7 +113,7 @@ internal class VideoCompressor @Inject constructor( deleteFile(destinationFile) VideoCompressionResult.CompressionNotNeeded } - else -> { + else -> { // Should not happen... // Delete now the temporary file deleteFile(destinationFile) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerModule.kt index 7ea74225cdac822c43b0acd2ae7e42ea3998bbd9..89b5c44ef0b97e198b214b0b29f770da8cc57adf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/ContentScannerModule.kt @@ -49,9 +49,11 @@ internal abstract class ContentScannerModule { @Provides @ContentScannerDatabase @SessionScope - fun providesContentScannerRealmConfiguration(realmKeysUtils: RealmKeysUtils, - @SessionFilesDirectory directory: File, - @UserMd5 userMd5: String): RealmConfiguration { + fun providesContentScannerRealmConfiguration( + realmKeysUtils: RealmKeysUtils, + @SessionFilesDirectory directory: File, + @UserMd5 userMd5: String + ): RealmConfiguration { return RealmConfiguration.Builder() .directory(directory) .name("matrix-sdk-content-scanning.realm") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerEntityQueries.kt index e4b64a1a0e5442183d9183c7cb7cf74af40c4629..bb3051bc965167a51280f3bd683e713b07330f05 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/ContentScannerEntityQueries.kt @@ -31,10 +31,12 @@ internal fun ContentScanResultEntity.Companion.get(realm: Realm, attachmentUrl: .findFirst() } -internal fun ContentScanResultEntity.Companion.getOrCreate(realm: Realm, - attachmentUrl: String, - contentScannerUrl: String?, - currentTimeMillis: Long): ContentScanResultEntity { +internal fun ContentScanResultEntity.Companion.getOrCreate( + realm: Realm, + attachmentUrl: String, + contentScannerUrl: String?, + currentTimeMillis: Long +): ContentScanResultEntity { return ContentScanResultEntity.get(realm, attachmentUrl, contentScannerUrl) ?: realm.createObject<ContentScanResultEntity>().also { it.mediaUrl = attachmentUrl diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/RealmContentScannerStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/RealmContentScannerStore.kt index 27729d38c78679eeba49c8ea3ae9389fed8377a9..72dc15c1bdf2f67ec15200877997af380e558a1b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/RealmContentScannerStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/contentscanner/db/RealmContentScannerStore.kt @@ -106,7 +106,7 @@ internal class RealmContentScannerStore @Inject constructor( ScanState.IN_PROGRESS, ScanState.TRUSTED, ScanState.INFECTED -> true - else -> false + else -> false } } return isKnown diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/directory/DirectoryAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/directory/DirectoryAPI.kt index 19b9130fc4b6e7f63954c518fcb8d81a3f61d74f..488c61206b24afd25cf1439aea7faf4a21b6f2a6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/directory/DirectoryAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/directory/DirectoryAPI.kt @@ -49,16 +49,21 @@ internal interface DirectoryAPI { * @param body the body containing the new directory visibility */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "directory/list/room/{roomId}") - suspend fun setRoomDirectoryVisibility(@Path("roomId") roomId: String, - @Body body: RoomDirectoryVisibilityJson) + suspend fun setRoomDirectoryVisibility( + @Path("roomId") roomId: String, + @Body body: RoomDirectoryVisibilityJson + ) /** * Add alias to the room. * @param roomAlias the room alias. + * @param body the Json body */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "directory/room/{roomAlias}") - suspend fun addRoomAlias(@Path("roomAlias") roomAlias: String, - @Body body: AddRoomAliasBody) + suspend fun addRoomAlias( + @Path("roomAlias") roomAlias: String, + @Body body: AddRoomAliasBody + ) /** * Delete a room alias. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/download/ProgressResponseBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/download/ProgressResponseBody.kt index 4fd4fda7d1a9ea90c9c9ff357a0bb638cddc4aa9..4e0096b7dd6c40308d1b780b517d44c3f006bfde 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/download/ProgressResponseBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/download/ProgressResponseBody.kt @@ -27,7 +27,8 @@ import okio.buffer internal class ProgressResponseBody( private val responseBody: ResponseBody, private val chainUrl: String, - private val progressListener: ProgressListener) : ResponseBody() { + private val progressListener: ProgressListener +) : ResponseBody() { private var bufferedSource: BufferedSource? = null diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/DefaultFilterService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/DefaultFilterService.kt index 9a16b8fd4a1ccac85dfb47c9a127aaf7c22a974e..2e68d02d8ce6b6427e6c23bff27b209ea0f219ba 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/DefaultFilterService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/DefaultFilterService.kt @@ -21,8 +21,10 @@ import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.configureWith import javax.inject.Inject -internal class DefaultFilterService @Inject constructor(private val saveFilterTask: SaveFilterTask, - private val taskExecutor: TaskExecutor) : FilterService { +internal class DefaultFilterService @Inject constructor( + private val saveFilterTask: SaveFilterTask, + private val taskExecutor: TaskExecutor +) : FilterService { // TODO Pass a list of support events instead override fun setFilter(filterPreset: FilterService.FilterPreset) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterApi.kt index dab801360fd99e98aec6095020c76ba6b7437e6f..ac1e9a654ca8c6febcca0a0e5a8615ca6b990814 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterApi.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterApi.kt @@ -28,20 +28,24 @@ internal interface FilterApi { * Upload FilterBody to get a filter_id which can be used for /sync requests. * * @param userId the user id - * @param body the Json representation of a FilterBody object + * @param body the Json representation of a FilterBody object */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/filter") - suspend fun uploadFilter(@Path("userId") userId: String, - @Body body: Filter): FilterResponse + suspend fun uploadFilter( + @Path("userId") userId: String, + @Body body: Filter + ): FilterResponse /** * Gets a filter with a given filterId from the homeserver. * - * @param userId the user id + * @param userId the user id * @param filterId the filterID * @return Filter */ @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/filter/{filterId}") - suspend fun getFilterById(@Path("userId") userId: String, - @Path("filterId") filterId: String): Filter + suspend fun getFilterById( + @Path("userId") userId: String, + @Path("filterId") filterId: String + ): Filter } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterUtil.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterUtil.kt index 562fea88b66c0b7fc015f98f2fe75b26618900b6..2017a86c39d100879746aaab4e42fda7459a390a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterUtil.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/FilterUtil.kt @@ -25,7 +25,7 @@ internal object FilterUtil { * FIXME New expected filter: * "{\"room\": {\"ephemeral\": {\"notTypes\": [\"m.typing\"]}}, \"presence\":{\"notTypes\": [\"*\"]}}" * - * @param filterBody filterBody to patch + * @param filterBody filterBody to patch * @param useDataSaveMode true to enable data save mode */ /* diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/SaveFilterTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/SaveFilterTask.kt index e9d5b876a8d14512ec122aa72bdc9ab65589aea9..63afa1bbbc4a1bdf1c0dba08e1121caab3b44de8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/SaveFilterTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/filter/SaveFilterTask.kt @@ -45,7 +45,7 @@ internal class DefaultSaveFilterTask @Inject constructor( FilterService.FilterPreset.ElementFilter -> { FilterFactory.createElementFilter() } - FilterService.FilterPreset.NoFilter -> { + FilterService.FilterPreset.NoFilter -> { FilterFactory.createDefaultFilter() } } @@ -53,7 +53,7 @@ internal class DefaultSaveFilterTask @Inject constructor( FilterService.FilterPreset.ElementFilter -> { FilterFactory.createElementRoomFilter() } - FilterService.FilterPreset.NoFilter -> { + FilterService.FilterPreset.NoFilter -> { FilterFactory.createDefaultRoomFilter() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/DefaultGroup.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/DefaultGroup.kt index 4f610fd81bfe4176c6febcd8a89bfb80cc499e41..9c37d4db6c9ff2fafbc13159f7eef14d944dd083 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/DefaultGroup.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/DefaultGroup.kt @@ -18,8 +18,10 @@ package org.matrix.android.sdk.internal.session.group import org.matrix.android.sdk.api.session.group.Group -internal class DefaultGroup(override val groupId: String, - private val getGroupDataTask: GetGroupDataTask) : Group { +internal class DefaultGroup( + override val groupId: String, + private val getGroupDataTask: GetGroupDataTask +) : Group { override suspend fun fetchGroupData() { val params = GetGroupDataTask.Params.FetchWithIds(listOf(groupId)) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataTask.kt index 4e0ee3422b5e44721de045f68b62fad69c8f5266..235291d0617251bc28925e872fc7e555f9c09e1e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/group/GetGroupDataTask.kt @@ -58,7 +58,7 @@ internal class DefaultGetGroupDataTask @Inject constructor( is GetGroupDataTask.Params.FetchAllActive -> { getActiveGroupIds() } - is GetGroupDataTask.Params.FetchWithIds -> { + is GetGroupDataTask.Params.FetchWithIds -> { params.groupIds } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt index e9097e4d033f0721bc0f49d967413e7838be0f7f..d22da8f6f2102a4f6ce0cae9f318f06cbc5f117c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt @@ -17,7 +17,7 @@ package org.matrix.android.sdk.internal.session.homeserver import com.zhuinden.monarchy.Monarchy -import org.matrix.android.sdk.api.MatrixPatterns.getDomain +import org.matrix.android.sdk.api.MatrixPatterns.getServerName import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.wellknown.WellknownResult import org.matrix.android.sdk.api.extensions.orFalse @@ -93,10 +93,14 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( } }.getOrNull() + // Domain may include a port (eg, matrix.org:8080) + // Per https://spec.matrix.org/latest/client-server-api/#well-known-uri we should extract the hostname from the server name + // So we take everything before the last : as the domain for the well-known task. + // NB: This is not always the same endpoint as capabilities / mediaConfig uses. val wellknownResult = runCatching { getWellknownTask.execute( GetWellknownTask.Params( - domain = userId.getDomain(), + domain = userId.getServerName().substringBeforeLast(":"), homeServerConnectionConfig = homeServerConnectionConfig ) ) @@ -105,10 +109,12 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( insertInDb(capabilities, mediaConfig, versions, wellknownResult) } - private suspend fun insertInDb(getCapabilitiesResult: GetCapabilitiesResult?, - getMediaConfigResult: GetMediaConfigResult?, - getVersionResult: Versions?, - getWellknownResult: WellknownResult?) { + private suspend fun insertInDb( + getCapabilitiesResult: GetCapabilitiesResult?, + getMediaConfigResult: GetMediaConfigResult?, + getVersionResult: Versions?, + getWellknownResult: WellknownResult? + ) { monarchy.awaitTransaction { realm -> val homeServerCapabilitiesEntity = HomeServerCapabilitiesEntity.getOrCreate(realm) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerPinger.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerPinger.kt index 70e1e551aa0e0384edcf637b351311341d7dbfc7..a3d6b7fa4988f7937dd5110859215478adf3f26e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerPinger.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerPinger.kt @@ -22,8 +22,10 @@ import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.task.TaskExecutor import javax.inject.Inject -internal class HomeServerPinger @Inject constructor(private val taskExecutor: TaskExecutor, - private val capabilitiesAPI: CapabilitiesAPI) { +internal class HomeServerPinger @Inject constructor( + private val taskExecutor: TaskExecutor, + private val capabilitiesAPI: CapabilitiesAPI +) { fun canReachHomeServer(callback: (Boolean) -> Unit) { taskExecutor.executorScope.launch { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt index 74838afc6587b6eacfd4b58a2550f3c0a9db8dcf..30c7773a8e794dd01fdecfb6b9429c10d404dec2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt @@ -283,8 +283,8 @@ internal class DefaultIdentityService @Inject constructor( identityStore.setToken(null) lookUpInternal(false, threePids) } - throwable.isTermsNotSigned() -> throw IdentityServiceError.TermsNotSignedException - else -> throw throwable + throwable.isTermsNotSigned() -> throw IdentityServiceError.TermsNotSignedException + else -> throw throwable } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAPI.kt index aef86ed08efaed4a3fe1feee081a4c304ff2e056..7b04bc52b03fc2c13ef17c09e824d86d9a3cdca2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAPI.kt @@ -95,8 +95,10 @@ internal interface IdentityAPI { * - https://matrix.org/docs/spec/identity_service/latest#post-matrix-identity-v2-validate-email-submittoken */ @POST(NetworkConstants.URI_IDENTITY_PATH_V2 + "validate/{medium}/submitToken") - suspend fun submitToken(@Path("medium") medium: String, - @Body body: IdentityRequestOwnershipParams): SuccessResult + suspend fun submitToken( + @Path("medium") medium: String, + @Body body: IdentityRequestOwnershipParams + ): SuccessResult /** * https://matrix.org/docs/spec/identity_service/r0.3.0#post-matrix-identity-v2-sign-ed25519. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt index f642ed4cf2f936574cf2de6366eac908f2b20396..21b59cca9dea70d4dc49c0913f08e05f19ed2bfd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt @@ -75,10 +75,12 @@ internal class DefaultIdentityBulkLookupTask @Inject constructor( val identityLookUpResponse: IdentityLookUpResponse ) - private suspend fun lookUpInternal(identityAPI: IdentityAPI, - threePids: List<ThreePid>, - hashDetailResponse: IdentityHashDetailResponse, - canRetry: Boolean): LookUpData { + private suspend fun lookUpInternal( + identityAPI: IdentityAPI, + threePids: List<ThreePid>, + hashDetailResponse: IdentityHashDetailResponse, + canRetry: Boolean + ): LookUpData { val hashedAddresses = getHashedAddresses(threePids, hashDetailResponse.pepper) return try { LookUpData(hashedAddresses, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt index 4e9d7dc7f764cad6d5cd0cee2265c6e3663d14e8..464ae96e3a4eda60f5fd7125767d257117e7bbe0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt @@ -47,8 +47,10 @@ internal abstract class IdentityModule { @Provides @SessionScope @AuthenticatedIdentity - fun providesOkHttpClient(@UnauthenticatedWithCertificate okHttpClient: OkHttpClient, - @AuthenticatedIdentity accessTokenProvider: AccessTokenProvider): OkHttpClient { + fun providesOkHttpClient( + @UnauthenticatedWithCertificate okHttpClient: OkHttpClient, + @AuthenticatedIdentity accessTokenProvider: AccessTokenProvider + ): OkHttpClient { return okHttpClient .newBuilder() .addAccessTokenInterceptor(accessTokenProvider) @@ -59,10 +61,12 @@ internal abstract class IdentityModule { @Provides @IdentityDatabase @SessionScope - fun providesIdentityRealmConfiguration(realmKeysUtils: RealmKeysUtils, - realmIdentityStoreMigration: RealmIdentityStoreMigration, - @SessionFilesDirectory directory: File, - @UserMd5 userMd5: String): RealmConfiguration { + fun providesIdentityRealmConfiguration( + realmKeysUtils: RealmKeysUtils, + realmIdentityStoreMigration: RealmIdentityStoreMigration, + @SessionFilesDirectory directory: File, + @UserMd5 userMd5: String + ): RealmConfiguration { return RealmConfiguration.Builder() .directory(directory) .name("matrix-sdk-identity.realm") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityRequestTokenForBindingTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityRequestTokenForBindingTask.kt index fe123096509fc4246693ec91a5cc3006ac0acbee..02462387fa1124f8a950db6116cb73259078870a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityRequestTokenForBindingTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityRequestTokenForBindingTask.kt @@ -57,7 +57,7 @@ internal class DefaultIdentityRequestTokenForBindingTask @Inject constructor( val tokenResponse = executeRequest(null) { when (params.threePid) { - is ThreePid.Email -> identityAPI.requestTokenToBindEmail( + is ThreePid.Email -> identityAPI.requestTokenToBindEmail( IdentityRequestTokenForEmailBody( clientSecret = clientSecret, sendAttempt = sendAttempt, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntityQuery.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntityQuery.kt index aecf21678c12576fff363146adc0bb39beb7818a..08e5b4397723198646578f39d6e23271b42d1aeb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntityQuery.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntityQuery.kt @@ -32,8 +32,10 @@ private fun IdentityDataEntity.Companion.getOrCreate(realm: Realm): IdentityData return get(realm) ?: realm.createObject() } -internal fun IdentityDataEntity.Companion.setUrl(realm: Realm, - url: String?) { +internal fun IdentityDataEntity.Companion.setUrl( + realm: Realm, + url: String? +) { realm.where<IdentityDataEntity>().findAll().deleteAllFromRealm() // Delete all pending binding if any IdentityPendingBindingEntity.deleteAll(realm) @@ -45,23 +47,29 @@ internal fun IdentityDataEntity.Companion.setUrl(realm: Realm, } } -internal fun IdentityDataEntity.Companion.setToken(realm: Realm, - newToken: String?) { +internal fun IdentityDataEntity.Companion.setToken( + realm: Realm, + newToken: String? +) { get(realm)?.apply { token = newToken } } -internal fun IdentityDataEntity.Companion.setUserConsent(realm: Realm, - newConsent: Boolean) { +internal fun IdentityDataEntity.Companion.setUserConsent( + realm: Realm, + newConsent: Boolean +) { get(realm)?.apply { userConsent = newConsent } } -internal fun IdentityDataEntity.Companion.setHashDetails(realm: Realm, - pepper: String, - algorithms: List<String>) { +internal fun IdentityDataEntity.Companion.setHashDetails( + realm: Realm, + pepper: String, + algorithms: List<String> +) { get(realm)?.apply { hashLookupPepper = pepper hashLookupAlgorithm = RealmList<String>().apply { addAll(algorithms) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/Extensions.kt deleted file mode 100644 index b40b1a56bfefd4c1a81271ef36477386b3129c95..0000000000000000000000000000000000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/Extensions.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2021 The Matrix.org Foundation C.I.C. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.matrix.android.sdk.internal.session.initsync - -import org.matrix.android.sdk.api.session.initsync.InitSyncStep - -internal inline fun <T> reportSubtask(reporter: ProgressReporter?, - initSyncStep: InitSyncStep, - totalProgress: Int, - parentWeight: Float, - block: () -> T): T { - reporter?.startTask(initSyncStep, totalProgress, parentWeight) - return block().also { - reporter?.endTask() - } -} - -internal inline fun <K, V, R> Map<out K, V>.mapWithProgress(reporter: ProgressReporter?, - initSyncStep: InitSyncStep, - parentWeight: Float, - transform: (Map.Entry<K, V>) -> R): List<R> { - var current = 0F - reporter?.startTask(initSyncStep, count() + 1, parentWeight) - return map { - reporter?.reportProgress(current) - current++ - transform.invoke(it) - }.also { - reporter?.endTask() - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt index 8034e5b9740632b1df5b272fa6fd44588300ef8a..7588037b46aafaf1069112f83e5873ff27bcd77f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/integrationmanager/IntegrationManager.kt @@ -54,11 +54,13 @@ import javax.inject.Inject * */ @SessionScope -internal class IntegrationManager @Inject constructor(matrixConfiguration: MatrixConfiguration, - @SessionDatabase private val monarchy: Monarchy, - private val updateUserAccountDataTask: UpdateUserAccountDataTask, - private val accountDataDataSource: UserAccountDataDataSource, - private val widgetFactory: WidgetFactory) : +internal class IntegrationManager @Inject constructor( + matrixConfiguration: MatrixConfiguration, + @SessionDatabase private val monarchy: Monarchy, + private val updateUserAccountDataTask: UpdateUserAccountDataTask, + private val accountDataDataSource: UserAccountDataDataSource, + private val widgetFactory: WidgetFactory +) : SessionLifecycleObserver { private val currentConfigs = ArrayList<IntegrationManagerConfig>() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt index 32bcf3f7ca8e6c36d682bcea3067c7d56649d73b..a31f0d606553ee9ad06b28905a2e5fc324bbe70f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/media/GetPreviewUrlTask.kt @@ -48,8 +48,8 @@ internal class DefaultGetPreviewUrlTask @Inject constructor( override suspend fun execute(params: GetPreviewUrlTask.Params): PreviewUrlData { return when (params.cacheStrategy) { - CacheStrategy.NoCache -> doRequest(params.url, params.timestamp) - is CacheStrategy.TtlCache -> doRequestWithCache( + CacheStrategy.NoCache -> doRequest(params.url, params.timestamp) + is CacheStrategy.TtlCache -> doRequestWithCache( params.url, params.timestamp, params.cacheStrategy.validityDurationInMillis, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt index a6ad025b8d769301d58ede89a545daf15410c2ec..5ab6aca88c75a0b17643645fc5884868fece08b1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/GetOpenIdTokenTask.kt @@ -28,7 +28,8 @@ internal interface GetOpenIdTokenTask : Task<Unit, OpenIdToken> internal class DefaultGetOpenIdTokenTask @Inject constructor( @UserId private val userId: String, private val openIdAPI: OpenIdAPI, - private val globalErrorReceiver: GlobalErrorReceiver) : GetOpenIdTokenTask { + private val globalErrorReceiver: GlobalErrorReceiver +) : GetOpenIdTokenTask { override suspend fun execute(params: Unit): OpenIdToken { return executeRequest(globalErrorReceiver) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/OpenIdAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/OpenIdAPI.kt index eb8c841d5771afb2c656d3a962842429628e3508..180ecbb1a3147ec94efac9b1c2d31986885bde0e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/OpenIdAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/openid/OpenIdAPI.kt @@ -32,8 +32,11 @@ internal interface OpenIdAPI { * Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-user-userid-openid-request-token * * @param userId the user id + * @param body an empty json body */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/openid/request_token") - suspend fun openIdToken(@Path("userId") userId: String, - @Body body: JsonDict = emptyMap()): OpenIdToken + suspend fun openIdToken( + @Path("userId") userId: String, + @Body body: JsonDict = emptyMap() + ): OpenIdToken } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt index f9da7b66f623ff96a116637bc69697ab0fa5bd9a..8e20199135a336d6a43e5edbf670370cc1e12706 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt @@ -44,15 +44,15 @@ internal class PermalinkFactory @Inject constructor( fun createPermalink(id: String, forceMatrixTo: Boolean): String? { return when { - id.isEmpty() -> null + id.isEmpty() -> null !useClientFormat(forceMatrixTo) -> MATRIX_TO_URL_BASE + escape(id) - else -> { + else -> { buildString { append(matrixConfiguration.clientPermalinkBaseUrl) when { MatrixPatterns.isRoomId(id) || MatrixPatterns.isRoomAlias(id) -> append(ROOM_PATH) - MatrixPatterns.isUserId(id) -> append(USER_PATH) - MatrixPatterns.isGroupId(id) -> append(GROUP_PATH) + MatrixPatterns.isUserId(id) -> append(USER_PATH) + MatrixPatterns.isGroupId(id) -> append(GROUP_PATH) } append(escape(id)) } @@ -94,16 +94,16 @@ internal class PermalinkFactory @Inject constructor( fun getLinkedId(url: String): String? { val clientBaseUrl = matrixConfiguration.clientPermalinkBaseUrl return when { - url.startsWith(MATRIX_TO_URL_BASE) -> url.substring(MATRIX_TO_URL_BASE.length) + url.startsWith(MATRIX_TO_URL_BASE) -> url.substring(MATRIX_TO_URL_BASE.length) clientBaseUrl != null && url.startsWith(clientBaseUrl) -> { when (PermalinkParser.parse(url)) { is PermalinkData.GroupLink -> url.substring(clientBaseUrl.length + GROUP_PATH.length) - is PermalinkData.RoomLink -> url.substring(clientBaseUrl.length + ROOM_PATH.length) - is PermalinkData.UserLink -> url.substring(clientBaseUrl.length + USER_PATH.length) - else -> null + is PermalinkData.RoomLink -> url.substring(clientBaseUrl.length + ROOM_PATH.length) + is PermalinkData.UserLink -> url.substring(clientBaseUrl.length + USER_PATH.length) + else -> null } } - else -> null + else -> null } ?.substringBeforeLast("?") } @@ -111,7 +111,7 @@ internal class PermalinkFactory @Inject constructor( fun createMentionSpanTemplate(type: PermalinkService.SpanTemplateType, forceMatrixTo: Boolean): String { return buildString { when (type) { - HTML -> append(MENTION_SPAN_TO_HTML_TEMPLATE_BEGIN) + HTML -> append(MENTION_SPAN_TO_HTML_TEMPLATE_BEGIN) MARKDOWN -> append(MENTION_SPAN_TO_MD_TEMPLATE_BEGIN) } append(baseUrl(forceMatrixTo)) @@ -119,7 +119,7 @@ internal class PermalinkFactory @Inject constructor( append(USER_PATH) } when (type) { - HTML -> append(MENTION_SPAN_TO_HTML_TEMPLATE_END) + HTML -> append(MENTION_SPAN_TO_HTML_TEMPLATE_END) MARKDOWN -> append(MENTION_SPAN_TO_MD_TEMPLATE_END) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt index 0f667c65df7562390eeab67ac24f37c19c56edd3..edc45fe94549b839c2e0b8096af61d38d539aaea 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/ViaParameterFinder.kt @@ -16,7 +16,7 @@ package org.matrix.android.sdk.internal.session.permalinks -import org.matrix.android.sdk.api.MatrixPatterns.getDomain +import org.matrix.android.sdk.api.MatrixPatterns.getServerName import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel @@ -55,9 +55,9 @@ internal class ViaParameterFinder @Inject constructor( } fun computeViaParams(userId: String, roomId: String, max: Int): List<String> { - val userHomeserver = userId.getDomain() + val userHomeserver = userId.getServerName() return getUserIdsOfJoinedMembers(roomId) - .map { it.getDomain() } + .map { it.getServerName() } .groupBy { it } .mapValues { it.value.size } .toMutableMap() @@ -92,7 +92,7 @@ internal class ViaParameterFinder @Inject constructor( .orEmpty() .toSet() - return userThatCanInvite.map { it.getDomain() } + return userThatCanInvite.map { it.getServerName() } .groupBy { it } .mapValues { it.value.size } .toMutableMap() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/PresenceAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/PresenceAPI.kt index 53d0d5e9631e8f7599545cc272e22e8866b48574..4af0307cb5eb95f0752a419f21190e414c6e3c09 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/PresenceAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/PresenceAPI.kt @@ -31,8 +31,10 @@ internal interface PresenceAPI { * Ref: https://matrix.org/docs/spec/client_server/latest#put-matrix-client-r0-presence-userid-status */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "presence/{userId}/status") - suspend fun setPresence(@Path("userId") userId: String, - @Body body: SetPresenceBody) + suspend fun setPresence( + @Path("userId") userId: String, + @Body body: SetPresenceBody + ) /** * Get the given user's presence state. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt index 678d3994284c65dccdc033e9aeebeab2a6900447..4a6cb6c019cebc7b099fca98285c8de8dd3d13ff 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt @@ -37,11 +37,12 @@ internal class DefaultAddThreePidTask @Inject constructor( private val profileAPI: ProfileAPI, @SessionDatabase private val monarchy: Monarchy, private val pendingThreePidMapper: PendingThreePidMapper, - private val globalErrorReceiver: GlobalErrorReceiver) : AddThreePidTask() { + private val globalErrorReceiver: GlobalErrorReceiver +) : AddThreePidTask() { override suspend fun execute(params: Params) { when (params.threePid) { - is ThreePid.Email -> addEmail(params.threePid) + is ThreePid.Email -> addEmail(params.threePid) is ThreePid.Msisdn -> addMsisdn(params.threePid) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/BindThreePidsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/BindThreePidsTask.kt index f630c2c225fc355106eb018adb2ddb49d177f798..5e892b32c3c8c8ad915b55e83261ec4d5a7813af 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/BindThreePidsTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/BindThreePidsTask.kt @@ -33,11 +33,12 @@ internal abstract class BindThreePidsTask : Task<BindThreePidsTask.Params, Unit> ) } -internal class DefaultBindThreePidsTask @Inject constructor(private val profileAPI: ProfileAPI, - private val identityStore: IdentityStore, - @AuthenticatedIdentity - private val accessTokenProvider: AccessTokenProvider, - private val globalErrorReceiver: GlobalErrorReceiver) : BindThreePidsTask() { +internal class DefaultBindThreePidsTask @Inject constructor( + private val profileAPI: ProfileAPI, + private val identityStore: IdentityStore, + @AuthenticatedIdentity private val accessTokenProvider: AccessTokenProvider, + private val globalErrorReceiver: GlobalErrorReceiver +) : BindThreePidsTask() { override suspend fun execute(params: Params) { val identityServerUrlWithoutProtocol = identityStore.getIdentityServerUrlWithoutProtocol() ?: throw IdentityServiceError.NoIdentityServerConfigured val identityServerAccessToken = accessTokenProvider.getToken() ?: throw IdentityServiceError.NoIdentityServerConfigured diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt index 5e64a6af0e2bc568989b4c75eab6ca892be9afa9..07765696619152693107ecaf1935ae108286f098 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt @@ -38,20 +38,22 @@ import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.configureWith import javax.inject.Inject -internal class DefaultProfileService @Inject constructor(private val taskExecutor: TaskExecutor, - @SessionDatabase private val monarchy: Monarchy, - private val coroutineDispatchers: MatrixCoroutineDispatchers, - private val refreshUserThreePidsTask: RefreshUserThreePidsTask, - private val getProfileInfoTask: GetProfileInfoTask, - private val setDisplayNameTask: SetDisplayNameTask, - private val setAvatarUrlTask: SetAvatarUrlTask, - private val addThreePidTask: AddThreePidTask, - private val validateSmsCodeTask: ValidateSmsCodeTask, - private val finalizeAddingThreePidTask: FinalizeAddingThreePidTask, - private val deleteThreePidTask: DeleteThreePidTask, - private val pendingThreePidMapper: PendingThreePidMapper, - private val userStore: UserStore, - private val fileUploader: FileUploader) : ProfileService { +internal class DefaultProfileService @Inject constructor( + private val taskExecutor: TaskExecutor, + @SessionDatabase private val monarchy: Monarchy, + private val coroutineDispatchers: MatrixCoroutineDispatchers, + private val refreshUserThreePidsTask: RefreshUserThreePidsTask, + private val getProfileInfoTask: GetProfileInfoTask, + private val setDisplayNameTask: SetDisplayNameTask, + private val setAvatarUrlTask: SetAvatarUrlTask, + private val addThreePidTask: AddThreePidTask, + private val validateSmsCodeTask: ValidateSmsCodeTask, + private val finalizeAddingThreePidTask: FinalizeAddingThreePidTask, + private val deleteThreePidTask: DeleteThreePidTask, + private val pendingThreePidMapper: PendingThreePidMapper, + private val userStore: UserStore, + private val fileUploader: FileUploader +) : ProfileService { override suspend fun getDisplayName(userId: String): Optional<String> { val params = GetProfileInfoTask.Params(userId) @@ -132,8 +134,10 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto validateSmsCodeTask.execute(ValidateSmsCodeTask.Params(threePid, code)) } - override suspend fun finalizeAddingThreePid(threePid: ThreePid, - userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor) { + override suspend fun finalizeAddingThreePid( + threePid: ThreePid, + userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor + ) { finalizeAddingThreePidTask .execute( FinalizeAddingThreePidTask.Params( @@ -165,8 +169,8 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto private fun UserThreePidEntity.asDomain(): ThreePid { return when (medium) { - ThirdPartyIdentifier.MEDIUM_EMAIL -> ThreePid.Email(address) + ThirdPartyIdentifier.MEDIUM_EMAIL -> ThreePid.Email(address) ThirdPartyIdentifier.MEDIUM_MSISDN -> ThreePid.Msisdn(address) - else -> error("Invalid medium type") + else -> error("Invalid medium type") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt index 7b7617aa8094906b8f453aef4066082aea354d3e..a8047a0118f0786f5758f503ba1d170d4365b6e0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt @@ -31,7 +31,8 @@ internal abstract class DeleteThreePidTask : Task<DeleteThreePidTask.Params, Uni internal class DefaultDeleteThreePidTask @Inject constructor( private val profileAPI: ProfileAPI, - private val globalErrorReceiver: GlobalErrorReceiver) : DeleteThreePidTask() { + private val globalErrorReceiver: GlobalErrorReceiver +) : DeleteThreePidTask() { override suspend fun execute(params: Params) { val body = DeleteThreePidBody( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt index 501aff63bd91b11c6455b270552198a9046081d6..89fcbca1ca64b18a8e8d403aaa23db86a35167d7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt @@ -47,7 +47,8 @@ internal class DefaultFinalizeAddingThreePidTask @Inject constructor( private val profileAPI: ProfileAPI, @SessionDatabase private val monarchy: Monarchy, private val pendingThreePidMapper: PendingThreePidMapper, - private val globalErrorReceiver: GlobalErrorReceiver) : FinalizeAddingThreePidTask() { + private val globalErrorReceiver: GlobalErrorReceiver +) : FinalizeAddingThreePidTask() { override suspend fun execute(params: Params) { val canCleanup = if (params.userWantsToCancel) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/GetProfileInfoTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/GetProfileInfoTask.kt index fed4288f849e0bae23f7da2f0a7e7d58d5ebabcd..40444edcab33143960c56678f460e7b6cffd875a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/GetProfileInfoTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/GetProfileInfoTask.kt @@ -29,8 +29,10 @@ internal abstract class GetProfileInfoTask : Task<GetProfileInfoTask.Params, Jso ) } -internal class DefaultGetProfileInfoTask @Inject constructor(private val profileAPI: ProfileAPI, - private val globalErrorReceiver: GlobalErrorReceiver) : GetProfileInfoTask() { +internal class DefaultGetProfileInfoTask @Inject constructor( + private val profileAPI: ProfileAPI, + private val globalErrorReceiver: GlobalErrorReceiver +) : GetProfileInfoTask() { override suspend fun execute(params: Params): JsonDict { return executeRequest(globalErrorReceiver) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt index 4d4506be76785f2d3365cabfd3848ad6c7f51d94..aa7f21d332ac28aec40a63d87e726d274fdfaa0e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt @@ -49,15 +49,19 @@ internal interface ProfileAPI { * Change user display name. */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}/displayname") - suspend fun setDisplayName(@Path("userId") userId: String, - @Body body: SetDisplayNameBody) + suspend fun setDisplayName( + @Path("userId") userId: String, + @Body body: SetDisplayNameBody + ) /** * Change user avatar url. */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}/avatar_url") - suspend fun setAvatarUrl(@Path("userId") userId: String, - @Body body: SetAvatarUrlBody) + suspend fun setAvatarUrl( + @Path("userId") userId: String, + @Body body: SetAvatarUrlBody + ) /** * Bind a threePid @@ -89,8 +93,10 @@ internal interface ProfileAPI { * Validate Msisdn code (same model than for identity server API). */ @POST - suspend fun validateMsisdn(@Url url: String, - @Body params: ValidationCodeBody): SuccessResult + suspend fun validateMsisdn( + @Url url: String, + @Body params: ValidationCodeBody + ): SuccessResult /** * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-3pid-add diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/RefreshUserThreePidsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/RefreshUserThreePidsTask.kt index 8a064b4fd12c93d98e70e0b7ffb8e19d3b03db76..8a25d870b67bd1f49d74433550c8236e24404282 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/RefreshUserThreePidsTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/RefreshUserThreePidsTask.kt @@ -28,9 +28,11 @@ import javax.inject.Inject internal abstract class RefreshUserThreePidsTask : Task<Unit, Unit> -internal class DefaultRefreshUserThreePidsTask @Inject constructor(private val profileAPI: ProfileAPI, - @SessionDatabase private val monarchy: Monarchy, - private val globalErrorReceiver: GlobalErrorReceiver) : RefreshUserThreePidsTask() { +internal class DefaultRefreshUserThreePidsTask @Inject constructor( + private val profileAPI: ProfileAPI, + @SessionDatabase private val monarchy: Monarchy, + private val globalErrorReceiver: GlobalErrorReceiver +) : RefreshUserThreePidsTask() { override suspend fun execute(params: Unit) { val accountThreePidsResponse = executeRequest(globalErrorReceiver) { @@ -55,9 +57,9 @@ internal class DefaultRefreshUserThreePidsTask @Inject constructor(private val p private fun Any?.toLong(): Long { return when (this) { - null -> 0L - is Long -> this + null -> 0L + is Long -> this is Double -> this.toLong() - else -> 0L + else -> 0L } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetAvatarUrlTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetAvatarUrlTask.kt index a7d116d919df94c6a64fc71f31abba8011f5df17..80282a894b17e426d048bad6c68f51fcf3db7d29 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetAvatarUrlTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetAvatarUrlTask.kt @@ -30,7 +30,8 @@ internal abstract class SetAvatarUrlTask : Task<SetAvatarUrlTask.Params, Unit> { internal class DefaultSetAvatarUrlTask @Inject constructor( private val profileAPI: ProfileAPI, - private val globalErrorReceiver: GlobalErrorReceiver) : SetAvatarUrlTask() { + private val globalErrorReceiver: GlobalErrorReceiver +) : SetAvatarUrlTask() { override suspend fun execute(params: Params) { val body = SetAvatarUrlBody( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetDisplayNameTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetDisplayNameTask.kt index 61d304231038a889a6f8ce5422d0029712ef7ea0..e3f04792b63464648aedcfcc94872335e25b8d0d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetDisplayNameTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/SetDisplayNameTask.kt @@ -30,7 +30,8 @@ internal abstract class SetDisplayNameTask : Task<SetDisplayNameTask.Params, Uni internal class DefaultSetDisplayNameTask @Inject constructor( private val profileAPI: ProfileAPI, - private val globalErrorReceiver: GlobalErrorReceiver) : SetDisplayNameTask() { + private val globalErrorReceiver: GlobalErrorReceiver +) : SetDisplayNameTask() { override suspend fun execute(params: Params) { val body = SetDisplayNameBody( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/UnbindThreePidsTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/UnbindThreePidsTask.kt index acbecc9fbee766050e12bf6f5815eef7eddd6cc2..2e2eb65bd41e8502e298d3270a9fc9c7bf796ace 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/UnbindThreePidsTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/UnbindThreePidsTask.kt @@ -32,9 +32,11 @@ internal abstract class UnbindThreePidsTask : Task<UnbindThreePidsTask.Params, B ) } -internal class DefaultUnbindThreePidsTask @Inject constructor(private val profileAPI: ProfileAPI, - private val identityStore: IdentityStore, - private val globalErrorReceiver: GlobalErrorReceiver) : UnbindThreePidsTask() { +internal class DefaultUnbindThreePidsTask @Inject constructor( + private val profileAPI: ProfileAPI, + private val identityStore: IdentityStore, + private val globalErrorReceiver: GlobalErrorReceiver +) : UnbindThreePidsTask() { override suspend fun execute(params: Params): Boolean { val identityServerUrlWithoutProtocol = identityStore.getIdentityServerUrlWithoutProtocol() ?: throw IdentityServiceError.NoIdentityServerConfigured diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPusherWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPusherWorker.kt index 0042558027746ef4422dd337825a27c21aeb083b..5fd50f175243878f63f35267a5d5acc8803e9595 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPusherWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/AddPusherWorker.kt @@ -53,7 +53,7 @@ internal class AddPusherWorker(context: Context, params: WorkerParameters, sessi } catch (exception: Throwable) { when (exception) { is Failure.NetworkConnection -> Result.retry() - else -> Result.failure() + else -> Result.failure() } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultConditionResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultConditionResolver.kt index 67fba390d00e1a5458060f005678a20a382fd047..ace5ee0b9a17d0448e8243deed3f27dfcc83d02d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultConditionResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultConditionResolver.kt @@ -34,18 +34,24 @@ internal class DefaultConditionResolver @Inject constructor( @UserId private val userId: String ) : ConditionResolver { - override fun resolveEventMatchCondition(event: Event, - condition: EventMatchCondition): Boolean { + override fun resolveEventMatchCondition( + event: Event, + condition: EventMatchCondition + ): Boolean { return condition.isSatisfied(event) } - override fun resolveRoomMemberCountCondition(event: Event, - condition: RoomMemberCountCondition): Boolean { + override fun resolveRoomMemberCountCondition( + event: Event, + condition: RoomMemberCountCondition + ): Boolean { return condition.isSatisfied(event, roomGetter) } - override fun resolveSenderNotificationPermissionCondition(event: Event, - condition: SenderNotificationPermissionCondition): Boolean { + override fun resolveSenderNotificationPermissionCondition( + event: Event, + condition: SenderNotificationPermissionCondition + ): Boolean { val roomId = event.roomId ?: return false val room = roomGetter.getRoom(roomId) ?: return false @@ -57,8 +63,10 @@ internal class DefaultConditionResolver @Inject constructor( return condition.isSatisfied(event, powerLevelsContent) } - override fun resolveContainsDisplayNameCondition(event: Event, - condition: ContainsDisplayNameCondition): Boolean { + override fun resolveContainsDisplayNameCondition( + event: Event, + condition: ContainsDisplayNameCondition + ): Boolean { val roomId = event.roomId ?: return false val room = roomGetter.getRoom(roomId) ?: return false val myDisplayName = room.membershipService().getRoomMember(userId)?.displayName ?: return false diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultPushersService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultPushersService.kt index 13b990a9ff5baeb0135c634d9ed156726535d7a8..e912d9ccf888986f31ea4fefd934224c84e2c192 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultPushersService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultPushersService.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.pushers import androidx.lifecycle.LiveData import androidx.work.BackoffPolicy import com.zhuinden.monarchy.Monarchy +import org.matrix.android.sdk.api.session.pushers.HttpPusher import org.matrix.android.sdk.api.session.pushers.Pusher import org.matrix.android.sdk.api.session.pushers.PushersService import org.matrix.android.sdk.internal.database.mapper.asDomain @@ -45,10 +46,12 @@ internal class DefaultPushersService @Inject constructor( private val taskExecutor: TaskExecutor ) : PushersService { - override suspend fun testPush(url: String, - appId: String, - pushkey: String, - eventId: String) { + override suspend fun testPush( + url: String, + appId: String, + pushkey: String, + eventId: String + ) { pushGatewayNotifyTask.execute(PushGatewayNotifyTask.Params(url, appId, pushkey, eventId)) } @@ -58,15 +61,15 @@ internal class DefaultPushersService @Inject constructor( .executeBy(taskExecutor) } - override fun enqueueAddHttpPusher(httpPusher: PushersService.HttpPusher): UUID { + override fun enqueueAddHttpPusher(httpPusher: HttpPusher): UUID { return enqueueAddPusher(httpPusher.toJsonPusher()) } - override suspend fun addHttpPusher(httpPusher: PushersService.HttpPusher) { + override suspend fun addHttpPusher(httpPusher: HttpPusher) { addPusherTask.execute(AddPusherTask.Params(httpPusher.toJsonPusher())) } - private fun PushersService.HttpPusher.toJsonPusher() = JsonPusher( + private fun HttpPusher.toJsonPusher() = JsonPusher( pushKey = pushkey, kind = "http", appId = appId, @@ -78,12 +81,14 @@ internal class DefaultPushersService @Inject constructor( append = append ) - override suspend fun addEmailPusher(email: String, - lang: String, - emailBranding: String, - appDisplayName: String, - deviceDisplayName: String, - append: Boolean) { + override suspend fun addEmailPusher( + email: String, + lang: String, + emailBranding: String, + appDisplayName: String, + deviceDisplayName: String, + append: Boolean + ) { addPusherTask.execute( AddPusherTask.Params( JsonPusher( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushRulesApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushRulesApi.kt index 40b4ee269ac8b3d82318f5c6c1e52af2438be1b1..1b316c78728c11bfb6dec813a7e9e984f3247d1d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushRulesApi.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushRulesApi.kt @@ -33,47 +33,55 @@ internal interface PushRulesApi { /** * Update the ruleID enable status. * - * @param kind the notification kind (sender, room...) + * @param kind the notification kind (sender, room...) * @param ruleId the ruleId - * @param enable the new enable status + * @param enabledBody the new enable status */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}/enabled") - suspend fun updateEnableRuleStatus(@Path("kind") kind: String, - @Path("ruleId") ruleId: String, - @Body enabledBody: EnabledBody) + suspend fun updateEnableRuleStatus( + @Path("kind") kind: String, + @Path("ruleId") ruleId: String, + @Body enabledBody: EnabledBody + ) /** * Update the ruleID action. * Ref: https://matrix.org/docs/spec/client_server/latest#put-matrix-client-r0-pushrules-scope-kind-ruleid-actions * - * @param kind the notification kind (sender, room...) - * @param ruleId the ruleId + * @param kind the notification kind (sender, room...) + * @param ruleId the ruleId * @param actions the actions */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}/actions") - suspend fun updateRuleActions(@Path("kind") kind: String, - @Path("ruleId") ruleId: String, - @Body actions: Any) + suspend fun updateRuleActions( + @Path("kind") kind: String, + @Path("ruleId") ruleId: String, + @Body actions: Any + ) /** * Delete a rule. * - * @param kind the notification kind (sender, room...) + * @param kind the notification kind (sender, room...) * @param ruleId the ruleId */ @DELETE(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}") - suspend fun deleteRule(@Path("kind") kind: String, - @Path("ruleId") ruleId: String) + suspend fun deleteRule( + @Path("kind") kind: String, + @Path("ruleId") ruleId: String + ) /** * Add the ruleID enable status. * - * @param kind the notification kind (sender, room...) + * @param kind the notification kind (sender, room...) * @param ruleId the ruleId. - * @param rule the rule to add. + * @param rule the rule to add. */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}") - suspend fun addRule(@Path("kind") kind: String, - @Path("ruleId") ruleId: String, - @Body rule: PushRule) + suspend fun addRule( + @Path("kind") kind: String, + @Path("ruleId") ruleId: String, + @Body rule: PushRule + ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePusherTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePusherTask.kt index 057c309078586c4980eb1e6cda71026fb6c8533e..86ba33cb98e9c2485ffbd1ef335514564110e72f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePusherTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/RemovePusherTask.kt @@ -30,8 +30,10 @@ import org.matrix.android.sdk.internal.util.awaitTransaction import javax.inject.Inject internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> { - data class Params(val pushKey: String, - val pushAppId: String) + data class Params( + val pushKey: String, + val pushAppId: String + ) } internal class DefaultRemovePusherTask @Inject constructor( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt index 815661a1ce9863170b2d10e29ee6aa120f8b1d9c..a923f1932b3813795198860e10f40b88d1b1ff9d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/UpdatePushRuleEnableStatusTask.kt @@ -23,9 +23,11 @@ import org.matrix.android.sdk.internal.task.Task import javax.inject.Inject internal interface UpdatePushRuleEnableStatusTask : Task<UpdatePushRuleEnableStatusTask.Params, Unit> { - data class Params(val kind: RuleKind, - val pushRule: PushRule, - val enabled: Boolean) + data class Params( + val kind: RuleKind, + val pushRule: PushRule, + val enabled: Boolean + ) } internal class DefaultUpdatePushRuleEnableStatusTask @Inject constructor( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt index 60c1194708307859e2060ae2d42251f8d540d042..09d7d50ecb86091eb0d2bdfa20f59e1f2bf7282b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt @@ -62,7 +62,7 @@ internal class DefaultProcessEventForPushTask @Inject constructor( EventType.REDACTION, EventType.ENCRYPTED, EventType.STATE_ROOM_MEMBER -> true - else -> false + else -> false } }.filter { it.senderId != userId diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt index 7326adee4c7a1a1d68ad1a3283046c57f3056606..abea2d34cd210834c680d81dc819b5346ecaf17a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt @@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataServic import org.matrix.android.sdk.api.session.room.alias.AliasService import org.matrix.android.sdk.api.session.room.call.RoomCallService import org.matrix.android.sdk.api.session.room.crypto.RoomCryptoService +import org.matrix.android.sdk.api.session.room.location.LocationSharingService import org.matrix.android.sdk.api.session.room.members.MembershipService import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.RoomType @@ -69,6 +70,7 @@ internal class DefaultRoom( private val roomAccountDataService: RoomAccountDataService, private val roomVersionService: RoomVersionService, private val viaParameterFinder: ViaParameterFinder, + private val locationSharingService: LocationSharingService, override val coroutineDispatchers: MatrixCoroutineDispatchers ) : Room { @@ -104,4 +106,5 @@ internal class DefaultRoom( override fun roomPushRuleService() = roomPushRuleService override fun roomAccountDataService() = roomAccountDataService override fun roomVersionService() = roomVersionService + override fun locationSharingService() = locationSharingService } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt index 7330c91c202d0f088f87b7bbcaf0217e98369292..1edc4c1e66ea5059cfcce384e0b4c57ea450adea 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomDirectoryService.kt @@ -35,8 +35,10 @@ internal class DefaultRoomDirectoryService @Inject constructor( private val roomAliasAvailabilityChecker: RoomAliasAvailabilityChecker ) : RoomDirectoryService { - override suspend fun getPublicRooms(server: String?, - publicRoomsParams: PublicRoomsParams): PublicRoomsResponse { + override suspend fun getPublicRooms( + server: String?, + publicRoomsParams: PublicRoomsParams + ): PublicRoomsResponse { return getPublicRoomTask.execute(GetPublicRoomTask.Params(server, publicRoomsParams)) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt index 8424ee8a36384a5ea91e8c223f2f958fd67b589e..5e6d052443d0c54b0742eaf3f12692bf51592d74 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoomService.kt @@ -20,7 +20,6 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import androidx.paging.PagedList import com.zhuinden.monarchy.Monarchy -import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.identity.model.SignInvitationResult import org.matrix.android.sdk.api.session.room.Room @@ -91,18 +90,27 @@ internal class DefaultRoomService @Inject constructor( return roomSummaryDataSource.getRoomSummary(roomIdOrAlias) } - override fun getRoomSummaries(queryParams: RoomSummaryQueryParams, - sortOrder: RoomSortOrder): List<RoomSummary> { + override fun getRoomSummaryLive(roomId: String): LiveData<Optional<RoomSummary>> { + return roomSummaryDataSource.getRoomSummaryLive(roomId) + } + + override fun getRoomSummaries( + queryParams: RoomSummaryQueryParams, + sortOrder: RoomSortOrder + ): List<RoomSummary> { return roomSummaryDataSource.getRoomSummaries(queryParams, sortOrder) } override fun refreshJoinedRoomSummaryPreviews(roomId: String?) { - val roomSummaries = getRoomSummaries(roomSummaryQueryParams { - if (roomId != null) { - this.roomId = QueryStringValue.Equals(roomId) - } - memberships = listOf(Membership.JOIN) - }) + val roomSummaries = if (roomId == null) { + getRoomSummaries(roomSummaryQueryParams { + memberships = listOf(Membership.JOIN) + }) + } else { + listOfNotNull( + getRoomSummary(roomId)?.takeIf { it.membership == Membership.JOIN } + ) + } if (roomSummaries.isNotEmpty()) { monarchy.runTransactionSync { realm -> @@ -113,21 +121,28 @@ internal class DefaultRoomService @Inject constructor( } } - override fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams, - sortOrder: RoomSortOrder): LiveData<List<RoomSummary>> { + override fun getRoomSummariesLive( + queryParams: RoomSummaryQueryParams, + sortOrder: RoomSortOrder + ): LiveData<List<RoomSummary>> { return roomSummaryDataSource.getRoomSummariesLive(queryParams, sortOrder) } - override fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, - pagedListConfig: PagedList.Config, - sortOrder: RoomSortOrder): LiveData<PagedList<RoomSummary>> { + override fun getPagedRoomSummariesLive( + queryParams: RoomSummaryQueryParams, + pagedListConfig: PagedList.Config, + sortOrder: RoomSortOrder + ): LiveData<PagedList<RoomSummary>> { return roomSummaryDataSource.getSortedPagedRoomSummariesLive(queryParams, pagedListConfig, sortOrder) } - override fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, - pagedListConfig: PagedList.Config, - sortOrder: RoomSortOrder): UpdatableLivePageResult { - return roomSummaryDataSource.getUpdatablePagedRoomSummariesLive(queryParams, pagedListConfig, sortOrder) + override fun getFilteredPagedRoomSummariesLive( + queryParams: RoomSummaryQueryParams, + pagedListConfig: PagedList.Config, + sortOrder: RoomSortOrder, + getFlattenParents: Boolean + ): UpdatableLivePageResult { + return roomSummaryDataSource.getUpdatablePagedRoomSummariesLive(queryParams, pagedListConfig, sortOrder, getFlattenParents) } override fun getRoomCountLive(queryParams: RoomSummaryQueryParams): LiveData<Int> { @@ -154,9 +169,11 @@ internal class DefaultRoomService @Inject constructor( joinRoomTask.execute(JoinRoomTask.Params(roomIdOrAlias, reason, viaServers)) } - override suspend fun joinRoom(roomId: String, - reason: String?, - thirdPartySigned: SignInvitationResult) { + override suspend fun joinRoom( + roomId: String, + reason: String?, + thirdPartySigned: SignInvitationResult + ) { joinRoomTask.execute(JoinRoomTask.Params(roomId, reason, thirdPartySigned = thirdPartySigned)) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index 16a63a9a96afb152dee055d4b9e3cb74ae5473dc..bb43d90328b90c4b4b6cb9b9865e0df55bf4aa44 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -16,7 +16,6 @@ package org.matrix.android.sdk.internal.session.room import io.realm.Realm -import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.crypto.verification.VerificationState import org.matrix.android.sdk.api.session.events.model.AggregatedAnnotation @@ -28,23 +27,16 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventCon import org.matrix.android.sdk.api.session.events.model.getRelationContent import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel -import org.matrix.android.sdk.api.session.room.getTimelineEvent -import org.matrix.android.sdk.api.session.room.model.PollSummaryContent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent -import org.matrix.android.sdk.api.session.room.model.VoteInfo -import org.matrix.android.sdk.api.session.room.model.VoteSummary import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent import org.matrix.android.sdk.api.session.room.model.message.MessageContent -import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper -import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent -import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent import org.matrix.android.sdk.internal.SessionManager import org.matrix.android.sdk.internal.crypto.verification.toState import org.matrix.android.sdk.internal.database.helper.findRootThreadEvent @@ -55,7 +47,6 @@ import org.matrix.android.sdk.internal.database.model.EditionOfEvent import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity import org.matrix.android.sdk.internal.database.model.EventEntity import org.matrix.android.sdk.internal.database.model.EventInsertType -import org.matrix.android.sdk.internal.database.model.PollResponseAggregatedSummaryEntity import org.matrix.android.sdk.internal.database.model.ReactionAggregatedSummaryEntity import org.matrix.android.sdk.internal.database.model.ReactionAggregatedSummaryEntityFields import org.matrix.android.sdk.internal.database.model.ReferencesAggregatedSummaryEntity @@ -68,6 +59,7 @@ import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.LiveLocationAggregationProcessor +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollAggregationProcessor import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource import org.matrix.android.sdk.internal.util.time.Clock import timber.log.Timber @@ -79,6 +71,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( @SessionId private val sessionId: String, private val sessionManager: SessionManager, private val liveLocationAggregationProcessor: LiveLocationAggregationProcessor, + private val pollAggregationProcessor: PollAggregationProcessor, private val clock: Clock, ) : EventInsertLiveProcessor { @@ -110,12 +103,12 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "") when (event.type) { - EventType.REACTION -> { + EventType.REACTION -> { // we got a reaction!! Timber.v("###REACTION in room $roomId , reaction eventID ${event.eventId}") handleReaction(realm, event, roomId, isLocalEcho) } - EventType.MESSAGE -> { + EventType.MESSAGE -> { if (event.unsignedData?.relations?.annotations != null) { Timber.v("###REACTION Aggregation in room $roomId for event ${event.eventId}") handleInitialAggregatedRelations(realm, event, roomId, event.unsignedData.relations.annotations) @@ -141,7 +134,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( EventType.KEY_VERIFICATION_START, EventType.KEY_VERIFICATION_MAC, EventType.KEY_VERIFICATION_READY, - EventType.KEY_VERIFICATION_KEY -> { + EventType.KEY_VERIFICATION_KEY -> { Timber.v("## SAS REF in room $roomId for event ${event.eventId}") event.content.toModel<MessageRelationContent>()?.relatesTo?.let { if (it.type == RelationType.REFERENCE && it.eventId != null) { @@ -150,7 +143,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } } - EventType.ENCRYPTED -> { + EventType.ENCRYPTED -> { // Relation type is in clear val encryptedEventContent = event.content.toModel<EncryptedEventContent>() if (encryptedEventContent?.relatesTo?.type == RelationType.REPLACE || @@ -162,9 +155,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor( // A replace! handleReplace(realm, event, it, roomId, isLocalEcho, encryptedEventContent.relatesTo.eventId) } else if (event.getClearType() in EventType.POLL_RESPONSE) { - event.getClearContent().toModel<MessagePollResponseContent>(catchError = true)?.let { pollResponseContent -> - Timber.v("###RESPONSE in room $roomId for event ${event.eventId}") - handleResponse(realm, event, pollResponseContent, roomId, isLocalEcho, encryptedEventContent.relatesTo.eventId) + sessionManager.getSessionComponent(sessionId)?.session()?.let { session -> + pollAggregationProcessor.handlePollResponseEvent(session, realm, event) } } } @@ -176,26 +168,28 @@ internal class EventRelationsAggregationProcessor @Inject constructor( EventType.KEY_VERIFICATION_START, EventType.KEY_VERIFICATION_MAC, EventType.KEY_VERIFICATION_READY, - EventType.KEY_VERIFICATION_KEY -> { + EventType.KEY_VERIFICATION_KEY -> { Timber.v("## SAS REF in room $roomId for event ${event.eventId}") encryptedEventContent.relatesTo.eventId?.let { handleVerification(realm, event, roomId, isLocalEcho, it) } } - in EventType.POLL_RESPONSE -> { + in EventType.POLL_RESPONSE -> { event.getClearContent().toModel<MessagePollResponseContent>(catchError = true)?.let { - handleResponse(realm, event, it, roomId, isLocalEcho, event.getRelationContent()?.eventId) + sessionManager.getSessionComponent(sessionId)?.session()?.let { session -> + pollAggregationProcessor.handlePollResponseEvent(session, realm, event) + } } } - in EventType.POLL_END -> { - event.content.toModel<MessageEndPollContent>(catchError = true)?.let { - handleEndPoll(realm, event, it, roomId, isLocalEcho) + in EventType.POLL_END -> { + sessionManager.getSessionComponent(sessionId)?.session()?.let { session -> + getPowerLevelsHelper(event.roomId)?.let { + pollAggregationProcessor.handlePollEndEvent(session, it, realm, event) + } } } in EventType.BEACON_LOCATION_DATA -> { - event.getClearContent().toModel<MessageBeaconLocationDataContent>(catchError = true)?.let { - liveLocationAggregationProcessor.handleBeaconLocationData(realm, event, it, roomId, isLocalEcho) - } + handleBeaconLocationData(event, realm, roomId, isLocalEcho) } } } else if (encryptedEventContent?.relatesTo?.type == RelationType.ANNOTATION) { @@ -217,11 +211,11 @@ internal class EventRelationsAggregationProcessor @Inject constructor( // } // } } - EventType.REDACTION -> { + EventType.REDACTION -> { val eventToPrune = event.redacts?.let { EventEntity.where(realm, eventId = it).findFirst() } ?: return when (eventToPrune.type) { - EventType.MESSAGE -> { + EventType.MESSAGE -> { Timber.d("REDACTION for message ${eventToPrune.eventId}") // val unsignedData = EventMapper.map(eventToPrune).unsignedData // ?: UnsignedData(null, null) @@ -237,7 +231,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } } } - in EventType.POLL_START -> { + in EventType.POLL_START -> { val content: MessagePollContent? = event.content.toModel() if (content?.relatesTo?.type == RelationType.REPLACE) { Timber.v("###REPLACE in room $roomId for event ${event.eventId}") @@ -245,14 +239,18 @@ internal class EventRelationsAggregationProcessor @Inject constructor( handleReplace(realm, event, content, roomId, isLocalEcho) } } - in EventType.POLL_RESPONSE -> { + in EventType.POLL_RESPONSE -> { event.content.toModel<MessagePollResponseContent>(catchError = true)?.let { - handleResponse(realm, event, it, roomId, isLocalEcho) + sessionManager.getSessionComponent(sessionId)?.session()?.let { session -> + pollAggregationProcessor.handlePollResponseEvent(session, realm, event) + } } } - in EventType.POLL_END -> { - event.content.toModel<MessageEndPollContent>(catchError = true)?.let { - handleEndPoll(realm, event, it, roomId, isLocalEcho) + in EventType.POLL_END -> { + sessionManager.getSessionComponent(sessionId)?.session()?.let { session -> + getPowerLevelsHelper(event.roomId)?.let { + pollAggregationProcessor.handlePollEndEvent(session, it, realm, event) + } } } in EventType.STATE_ROOM_BEACON_INFO -> { @@ -260,7 +258,10 @@ internal class EventRelationsAggregationProcessor @Inject constructor( liveLocationAggregationProcessor.handleBeaconInfo(realm, event, it, roomId, isLocalEcho) } } - else -> Timber.v("UnHandled event ${event.eventId}") + in EventType.BEACON_LOCATION_DATA -> { + handleBeaconLocationData(event, realm, roomId, isLocalEcho) + } + else -> Timber.v("UnHandled event ${event.eventId}") } } catch (t: Throwable) { Timber.e(t, "## Should not happen ") @@ -270,12 +271,14 @@ internal class EventRelationsAggregationProcessor @Inject constructor( // OPT OUT serer aggregation until API mature enough private val SHOULD_HANDLE_SERVER_AGREGGATION = false // should be true to work with e2e - private fun handleReplace(realm: Realm, - event: Event, - content: MessageContent, - roomId: String, - isLocalEcho: Boolean, - relatedEventId: String? = null) { + private fun handleReplace( + realm: Realm, + event: Event, + content: MessageContent, + roomId: String, + isLocalEcho: Boolean, + relatedEventId: String? = null + ) { val eventId = event.eventId ?: return val targetEventId = relatedEventId ?: content.relatesTo?.eventId ?: return val newContent = content.newContent ?: return @@ -317,22 +320,6 @@ internal class EventRelationsAggregationProcessor @Inject constructor( return } - ContentMapper - .map(eventAnnotationsSummaryEntity.pollResponseSummary?.aggregatedContent) - ?.toModel<PollSummaryContent>() - ?.let { existingPollSummaryContent -> - eventAnnotationsSummaryEntity.pollResponseSummary?.aggregatedContent = ContentMapper.map( - PollSummaryContent( - myVote = existingPollSummaryContent.myVote, - votes = emptyList(), - votesSummary = emptyMap(), - totalVotes = 0, - winnerVoteCount = 0, - ) - .toContent() - ) - } - val txId = event.unsignedData?.transactionId // is it a remote echo? if (!isLocalEcho && existingSummary.editions.any { it.eventId == txId }) { @@ -362,6 +349,10 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } } + if (event.getClearType() in EventType.POLL_START) { + pollAggregationProcessor.handlePollStartEvent(realm, event) + } + if (!isLocalEcho) { val replaceEvent = TimelineEventEntity .where(realm, roomId, eventId) @@ -375,10 +366,13 @@ internal class EventRelationsAggregationProcessor @Inject constructor( * Check if the edition is on the latest thread event, and update it accordingly. * @param editedEvent The event that will be changed * @param replaceEvent The new event + * @param editions list of edition of event */ - private fun handleThreadSummaryEdition(editedEvent: EventEntity?, - replaceEvent: TimelineEventEntity?, - editions: List<EditionOfEvent>?) { + private fun handleThreadSummaryEdition( + editedEvent: EventEntity?, + replaceEvent: TimelineEventEntity?, + editions: List<EditionOfEvent>? + ) { replaceEvent ?: return editedEvent ?: return editedEvent.findRootThreadEvent()?.apply { @@ -391,179 +385,18 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } } - private fun handleResponse(realm: Realm, - event: Event, - content: MessagePollResponseContent, - roomId: String, - isLocalEcho: Boolean, - relatedEventId: String? = null) { - val eventId = event.eventId ?: return - val senderId = event.senderId ?: return - val targetEventId = relatedEventId ?: content.relatesTo?.eventId ?: return - val eventTimestamp = event.originServerTs ?: return - - val targetPollContent = getPollContent(roomId, targetEventId) ?: return - - // ok, this is a poll response - var existing = EventAnnotationsSummaryEntity.where(realm, roomId, targetEventId).findFirst() - if (existing == null) { - Timber.v("## POLL creating new relation summary for $targetEventId") - existing = EventAnnotationsSummaryEntity.create(realm, roomId, targetEventId) - } - - // we have it - val existingPollSummary = existing.pollResponseSummary - ?: realm.createObject(PollResponseAggregatedSummaryEntity::class.java).also { - existing.pollResponseSummary = it - } - - val closedTime = existingPollSummary.closedTime - if (closedTime != null && eventTimestamp > closedTime) { - Timber.v("## POLL is closed ignore event poll:$targetEventId, event :${event.eventId}") - return - } - - val currentModel = ContentMapper.map(existingPollSummary.aggregatedContent).toModel<PollSummaryContent>() - - if (existingPollSummary.sourceEvents.contains(eventId)) { - // ignore this event, we already know it (??) - Timber.v("## POLL ignoring event for summary, it's known eventId:$eventId") - return - } - val txId = event.unsignedData?.transactionId - // is it a remote echo? - if (!isLocalEcho && existingPollSummary.sourceLocalEchoEvents.contains(txId)) { - // ok it has already been managed - Timber.v("## POLL Receiving remote echo of response eventId:$eventId") - existingPollSummary.sourceLocalEchoEvents.remove(txId) - existingPollSummary.sourceEvents.add(event.eventId) - return - } - - val option = content.getBestResponse()?.answers?.first() ?: return Unit.also { - Timber.d("## POLL Ignoring malformed response no option eventId:$eventId content: ${event.content}") - } - - // Check if this option is in available options - if (!targetPollContent.getBestPollCreationInfo()?.answers?.map { it.id }?.contains(option).orFalse()) { - Timber.v("## POLL $targetEventId doesn't contain option $option") - return - } - - val votes = currentModel?.votes.orEmpty().toMutableList() - - var myVote: String? = null - val existingVoteIndex = votes.indexOfFirst { it.userId == senderId } - if (existingVoteIndex != -1) { - // Is the vote newer? - val existingVote = votes[existingVoteIndex] - if (existingVote.voteTimestamp < eventTimestamp) { - // Take the new one - votes[existingVoteIndex] = VoteInfo(senderId, option, eventTimestamp) - if (userId == senderId) { - myVote = option - } - Timber.v("## POLL adding vote $option for user $senderId in poll :$targetEventId ") - } else { - Timber.v("## POLL Ignoring vote (older than known one) eventId:$eventId ") - } - } else { - votes.add(VoteInfo(senderId, option, eventTimestamp)) - if (userId == senderId) { - myVote = option - } - Timber.v("## POLL adding vote $option for user $senderId in poll :$targetEventId ") - } - - // Precompute the percentage of votes for all options - val totalVotes = votes.size - val newVotesSummary = votes - .groupBy({ it.option }, { it.userId }) - .mapValues { - VoteSummary( - total = it.value.size, - percentage = if (totalVotes == 0 && it.value.isEmpty()) 0.0 else it.value.size.toDouble() / totalVotes - ) - } - val newWinnerVoteCount = newVotesSummary.maxOf { it.value.total } - - if (isLocalEcho) { - existingPollSummary.sourceLocalEchoEvents.add(eventId) - } else { - existingPollSummary.sourceEvents.add(eventId) - } - - val newSumModel = PollSummaryContent( - myVote = myVote, - votes = votes, - votesSummary = newVotesSummary, - totalVotes = totalVotes, - winnerVoteCount = newWinnerVoteCount - ) - - existingPollSummary.aggregatedContent = ContentMapper.map(newSumModel.toContent()) - } - - private fun handleEndPoll(realm: Realm, - event: Event, - content: MessageEndPollContent, - roomId: String, - isLocalEcho: Boolean) { - val pollEventId = content.relatesTo?.eventId ?: return - val pollOwnerId = getPollEvent(roomId, pollEventId)?.root?.senderId - val isPollOwner = pollOwnerId == event.senderId - val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) + private fun getPowerLevelsHelper(roomId: String): PowerLevelsHelper? { + return stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) ?.content?.toModel<PowerLevelsContent>() ?.let { PowerLevelsHelper(it) } - - if (!isPollOwner && !powerLevelsHelper?.isUserAbleToRedact(event.senderId ?: "").orFalse()) { - Timber.v("## Received poll.end event $pollEventId but user ${event.senderId} doesn't have enough power level in room $roomId") - return - } - - var existingPoll = EventAnnotationsSummaryEntity.where(realm, roomId, pollEventId).findFirst() - if (existingPoll == null) { - Timber.v("## POLL creating new relation summary for $pollEventId") - existingPoll = EventAnnotationsSummaryEntity.create(realm, roomId, pollEventId) - } - - // we have it - val existingPollSummary = existingPoll.pollResponseSummary - ?: realm.createObject(PollResponseAggregatedSummaryEntity::class.java).also { - existingPoll.pollResponseSummary = it - } - - val txId = event.unsignedData?.transactionId - existingPollSummary.closedTime = event.originServerTs - - // is it a remote echo? - if (!isLocalEcho && existingPollSummary.sourceLocalEchoEvents.contains(txId)) { - // ok it has already been managed - Timber.v("## POLL Receiving remote echo of response eventId:$pollEventId") - existingPollSummary.sourceLocalEchoEvents.remove(txId) - existingPollSummary.sourceEvents.add(event.eventId) - } } - private fun getPollEvent(roomId: String, eventId: String): TimelineEvent? { - val session = sessionManager.getSessionComponent(sessionId)?.session() - return session?.roomService()?.getRoom(roomId)?.getTimelineEvent(eventId) ?: return null.also { - Timber.v("## POLL target poll event $eventId not found in room $roomId") - } - } - - private fun getPollContent(roomId: String, eventId: String): MessagePollContent? { - val pollEvent = getPollEvent(roomId, eventId) ?: return null - - return pollEvent.getLastMessageContent() as? MessagePollContent ?: return null.also { - Timber.v("## POLL target poll event $eventId content is malformed") - } - } - - private fun handleInitialAggregatedRelations(realm: Realm, - event: Event, - roomId: String, - aggregation: AggregatedAnnotation) { + private fun handleInitialAggregatedRelations( + realm: Realm, + event: Event, + roomId: String, + aggregation: AggregatedAnnotation + ) { if (SHOULD_HANDLE_SERVER_AGREGGATION) { aggregation.chunk?.forEach { if (it.type == EventType.REACTION) { @@ -585,10 +418,12 @@ internal class EventRelationsAggregationProcessor @Inject constructor( } } - private fun handleReaction(realm: Realm, - event: Event, - roomId: String, - isLocalEcho: Boolean) { + private fun handleReaction( + realm: Realm, + event: Event, + roomId: String, + isLocalEcho: Boolean + ) { val content = event.content.toModel<ReactionContent>() if (content == null) { Timber.e("Malformed reaction content ${event.content}") @@ -653,9 +488,11 @@ internal class EventRelationsAggregationProcessor @Inject constructor( /** * Called when an event is deleted. */ - private fun handleRedactionOfReplace(realm: Realm, - redacted: EventEntity, - relatedEventId: String) { + private fun handleRedactionOfReplace( + realm: Realm, + redacted: EventEntity, + relatedEventId: String + ) { Timber.d("Handle redaction of m.replace") val eventSummary = EventAnnotationsSummaryEntity.where(realm, redacted.roomId, relatedEventId).findFirst() if (eventSummary == null) { @@ -671,8 +508,10 @@ internal class EventRelationsAggregationProcessor @Inject constructor( sourceToDiscard.deleteFromRealm() } - private fun handleReactionRedact(realm: Realm, - eventToPrune: EventEntity) { + private fun handleReactionRedact( + realm: Realm, + eventToPrune: EventEntity + ) { Timber.v("REDACTION of reaction ${eventToPrune.eventId}") // delete a reaction, need to update the annotation summary if any val reactionContent: ReactionContent = EventMapper.map(eventToPrune).content.toModel() ?: return @@ -733,7 +572,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor( EventType.KEY_VERIFICATION_ACCEPT, EventType.KEY_VERIFICATION_READY, EventType.KEY_VERIFICATION_KEY, - EventType.KEY_VERIFICATION_MAC -> currentState.toState(VerificationState.WAITING) + EventType.KEY_VERIFICATION_MAC -> currentState.toState(VerificationState.WAITING) EventType.KEY_VERIFICATION_CANCEL -> currentState.toState( if (event.senderId == userId) { VerificationState.CANCELED_BY_ME @@ -741,8 +580,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor( VerificationState.CANCELED_BY_OTHER } ) - EventType.KEY_VERIFICATION_DONE -> currentState.toState(VerificationState.DONE) - else -> VerificationState.REQUEST + EventType.KEY_VERIFICATION_DONE -> currentState.toState(VerificationState.DONE) + else -> VerificationState.REQUEST } data = data.copy(verificationState = newState) @@ -756,4 +595,17 @@ internal class EventRelationsAggregationProcessor @Inject constructor( verifSummary.sourceEvents.add(event.eventId) } } + + private fun handleBeaconLocationData(event: Event, realm: Realm, roomId: String, isLocalEcho: Boolean) { + event.getClearContent().toModel<MessageBeaconLocationDataContent>(catchError = true)?.let { + liveLocationAggregationProcessor.handleBeaconLocationData( + realm, + event, + it, + roomId, + event.getRelationContent()?.eventId, + isLocalEcho + ) + } + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt index 72f56ddf688524128ec8a77b13b04daa8315f1b4..ac2880de69946da33fc1ddb58db47ce03a2d33f2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt @@ -58,8 +58,9 @@ internal interface RoomAPI { * Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-publicrooms */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "publicRooms") - suspend fun publicRooms(@Query("server") server: String?, - @Body publicRoomsParams: PublicRoomsParams + suspend fun publicRooms( + @Query("server") server: String?, + @Body publicRoomsParams: PublicRoomsParams ): PublicRoomsResponse /** @@ -78,138 +79,156 @@ internal interface RoomAPI { * Get a list of messages starting from a reference. * * @param roomId the room id - * @param from the token identifying where to start. Required. - * @param dir The direction to return messages from. Required. - * @param limit the maximum number of messages to retrieve. Optional. + * @param from the token identifying where to start. Required. + * @param dir The direction to return messages from. Required. + * @param limit the maximum number of messages to retrieve. Optional. * @param filter A JSON RoomEventFilter to filter returned events with. Optional. */ @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/messages") - suspend fun getRoomMessagesFrom(@Path("roomId") roomId: String, - @Query("from") from: String, - @Query("dir") dir: String, - @Query("limit") limit: Int?, - @Query("filter") filter: String? + suspend fun getRoomMessagesFrom( + @Path("roomId") roomId: String, + @Query("from") from: String, + @Query("dir") dir: String, + @Query("limit") limit: Int?, + @Query("filter") filter: String? ): PaginationResponse /** * Get all members of a room. * - * @param roomId the room id where to get the members - * @param syncToken the sync token (optional) - * @param membership to include only one type of membership (optional) + * @param roomId the room id where to get the members + * @param syncToken the sync token (optional) + * @param membership to include only one type of membership (optional) * @param notMembership to exclude one type of membership (optional) */ @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/members") - suspend fun getMembers(@Path("roomId") roomId: String, - @Query("at") syncToken: String?, - @Query("membership") membership: Membership?, - @Query("not_membership") notMembership: Membership? + suspend fun getMembers( + @Path("roomId") roomId: String, + @Query("at") syncToken: String?, + @Query("membership") membership: Membership?, + @Query("not_membership") notMembership: Membership? ): RoomMembersResponse /** * Send an event to a room. * - * @param txId the transaction Id - * @param roomId the room id + * @param txId the transaction Id + * @param roomId the room id * @param eventType the event type - * @param content the event content + * @param content the event content */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/send/{eventType}/{txId}") - suspend fun send(@Path("txId") txId: String, - @Path("roomId") roomId: String, - @Path("eventType") eventType: String, - @Body content: Content? + suspend fun send( + @Path("txId") txId: String, + @Path("roomId") roomId: String, + @Path("eventType") eventType: String, + @Body content: Content? ): SendResponse /** * Get the context surrounding an event. * - * @param roomId the room id + * @param roomId the room id * @param eventId the event Id - * @param limit the maximum number of messages to retrieve - * @param filter A JSON RoomEventFilter to filter returned events with. Optional. + * @param limit the maximum number of messages to retrieve + * @param filter A JSON RoomEventFilter to filter returned events with. Optional. */ @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/context/{eventId}") - suspend fun getContextOfEvent(@Path("roomId") roomId: String, - @Path("eventId") eventId: String, - @Query("limit") limit: Int, - @Query("filter") filter: String? = null): EventContextResponse + suspend fun getContextOfEvent( + @Path("roomId") roomId: String, + @Path("eventId") eventId: String, + @Query("limit") limit: Int, + @Query("filter") filter: String? = null + ): EventContextResponse /** * Retrieve an event from its room id / events id. * - * @param roomId the room id + * @param roomId the room id * @param eventId the event Id */ @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/event/{eventId}") - suspend fun getEvent(@Path("roomId") roomId: String, - @Path("eventId") eventId: String): Event + suspend fun getEvent( + @Path("roomId") roomId: String, + @Path("eventId") eventId: String + ): Event /** * Send read markers. * - * @param roomId the room id + * @param roomId the room id * @param markers the read markers */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/read_markers") - suspend fun sendReadMarker(@Path("roomId") roomId: String, - @Body markers: Map<String, String>) + suspend fun sendReadMarker( + @Path("roomId") roomId: String, + @Body markers: Map<String, String> + ) /** * Send receipt to a room. */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/receipt/{receiptType}/{eventId}") - suspend fun sendReceipt(@Path("roomId") roomId: String, - @Path("receiptType") receiptType: String, - @Path("eventId") eventId: String, - @Body body: JsonDict = emptyMap()) + suspend fun sendReceipt( + @Path("roomId") roomId: String, + @Path("receiptType") receiptType: String, + @Path("eventId") eventId: String, + @Body body: JsonDict = emptyMap() + ) /** * Invite a user to the given room. * Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-rooms-roomid-invite * * @param roomId the room id - * @param body a object that just contains a user id + * @param body a object that just contains a user id */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/invite") - suspend fun invite(@Path("roomId") roomId: String, - @Body body: InviteBody) + suspend fun invite( + @Path("roomId") roomId: String, + @Body body: InviteBody + ) /** * Invite a user to a room, using a ThreePid * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#id101 * @param roomId Required. The room identifier (not alias) to which to invite the user. + * @param body the Json body */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/invite") - suspend fun invite3pid(@Path("roomId") roomId: String, - @Body body: ThreePidInviteBody) + suspend fun invite3pid( + @Path("roomId") roomId: String, + @Body body: ThreePidInviteBody + ) /** * Send a generic state event. * - * @param roomId the room id. + * @param roomId the room id. * @param stateEventType the state event type - * @param params the request parameters + * @param params the request parameters */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/state/{state_event_type}") - suspend fun sendStateEvent(@Path("roomId") roomId: String, - @Path("state_event_type") stateEventType: String, - @Body params: JsonDict + suspend fun sendStateEvent( + @Path("roomId") roomId: String, + @Path("state_event_type") stateEventType: String, + @Body params: JsonDict ): SendResponse /** * Send a generic state event. * - * @param roomId the room id. + * @param roomId the room id. * @param stateEventType the state event type - * @param stateKey the state keys - * @param params the request parameters + * @param stateKey the state keys + * @param params the request parameters */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/state/{state_event_type}/{state_key}") - suspend fun sendStateEvent(@Path("roomId") roomId: String, - @Path("state_event_type") stateEventType: String, - @Path("state_key") stateKey: String, - @Body params: JsonDict + suspend fun sendStateEvent( + @Path("roomId") roomId: String, + @Path("state_event_type") stateEventType: String, + @Path("state_key") stateKey: String, + @Body params: JsonDict ): SendResponse /** @@ -221,30 +240,43 @@ internal interface RoomAPI { /** * Paginate relations for event based in normal topological order. + * @param roomId the room Id + * @param eventId the event Id * @param relationType filter for this relation type * @param eventType filter for this event type + * @param from from token + * @param to to token + * @param limit max number of Event to retrieve */ @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "rooms/{roomId}/relations/{eventId}/{relationType}/{eventType}") - suspend fun getRelations(@Path("roomId") roomId: String, - @Path("eventId") eventId: String, - @Path("relationType") relationType: String, - @Path("eventType") eventType: String, - @Query("from") from: String? = null, - @Query("to") to: String? = null, - @Query("limit") limit: Int? = null + suspend fun getRelations( + @Path("roomId") roomId: String, + @Path("eventId") eventId: String, + @Path("relationType") relationType: String, + @Path("eventType") eventType: String, + @Query("from") from: String? = null, + @Query("to") to: String? = null, + @Query("limit") limit: Int? = null ): RelationsResponse /** * Paginate relations for thread events based in normal topological order. + * + * @param roomId the room Id + * @param eventId the event Id * @param relationType filter for this relation type + * @param from from token + * @param to to token + * @param limit max number of Event to retrieve */ @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "rooms/{roomId}/relations/{eventId}/{relationType}") - suspend fun getThreadsRelations(@Path("roomId") roomId: String, - @Path("eventId") eventId: String, - @Path("relationType") relationType: String = RelationType.THREAD, - @Query("from") from: String? = null, - @Query("to") to: String? = null, - @Query("limit") limit: Int? = null + suspend fun getThreadsRelations( + @Path("roomId") roomId: String, + @Path("eventId") eventId: String, + @Path("relationType") relationType: String = RelationType.THREAD, + @Query("from") from: String? = null, + @Query("to") to: String? = null, + @Query("limit") limit: Int? = null ): RelationsResponse /** @@ -255,59 +287,69 @@ internal interface RoomAPI { * @param params the request body */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "join/{roomIdOrAlias}") - suspend fun join(@Path("roomIdOrAlias") roomIdOrAlias: String, - @Query("server_name") viaServers: List<String>, - @Body params: JsonDict): JoinRoomResponse + suspend fun join( + @Path("roomIdOrAlias") roomIdOrAlias: String, + @Query("server_name") viaServers: List<String>, + @Body params: JsonDict + ): JoinRoomResponse /** * Leave the given room. * - * @param roomId the room id + * @param roomId the room id * @param params the request body */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/leave") - suspend fun leave(@Path("roomId") roomId: String, - @Body params: Map<String, String?>) + suspend fun leave( + @Path("roomId") roomId: String, + @Body params: Map<String, String?> + ) /** * Ban a user from the given room. * - * @param roomId the room id + * @param roomId the room id * @param userIdAndReason the banned user object (userId and reason for ban) */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/ban") - suspend fun ban(@Path("roomId") roomId: String, - @Body userIdAndReason: UserIdAndReason) + suspend fun ban( + @Path("roomId") roomId: String, + @Body userIdAndReason: UserIdAndReason + ) /** * unban a user from the given room. * - * @param roomId the room id + * @param roomId the room id * @param userIdAndReason the unbanned user object (userId and reason for unban) */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/unban") - suspend fun unban(@Path("roomId") roomId: String, - @Body userIdAndReason: UserIdAndReason) + suspend fun unban( + @Path("roomId") roomId: String, + @Body userIdAndReason: UserIdAndReason + ) /** * Kick a user from the given room. * - * @param roomId the room id + * @param roomId the room id * @param userIdAndReason the kicked user object (userId and reason for kicking) */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/kick") - suspend fun kick(@Path("roomId") roomId: String, - @Body userIdAndReason: UserIdAndReason) + suspend fun kick( + @Path("roomId") roomId: String, + @Body userIdAndReason: UserIdAndReason + ) /** * Strips all information out of an event which isn't critical to the integrity of the server-side representation of the room. * This cannot be undone. * Users may redact their own events, and any user with a power level greater than or equal to the redact power level of the room may redact events there. * - * @param txId the transaction Id - * @param roomId the room id - * @param eventId the event to delete - * @param reason json containing reason key {"reason": "Indecent material"} + * @param txId the transaction Id + * @param roomId the room id + * @param eventId the event to delete + * @param reason json containing reason key {"reason": "Indecent material"} */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/redact/{eventId}/{txnId}") suspend fun redactEvent( @@ -320,14 +362,16 @@ internal interface RoomAPI { /** * Reports an event as inappropriate to the server, which may then notify the appropriate people. * - * @param roomId the room id + * @param roomId the room id * @param eventId the event to report content - * @param body body containing score and reason + * @param body body containing score and reason */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/report/{eventId}") - suspend fun reportContent(@Path("roomId") roomId: String, - @Path("eventId") eventId: String, - @Body body: ReportContentBody) + suspend fun reportContent( + @Path("roomId") roomId: String, + @Path("eventId") eventId: String, + @Body body: ReportContentBody + ) /** * Get a list of aliases maintained by the local server for the given room. @@ -340,9 +384,11 @@ internal interface RoomAPI { * Inform that the user is starting to type or has stopped typing. */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/typing/{userId}") - suspend fun sendTypingState(@Path("roomId") roomId: String, - @Path("userId") userId: String, - @Body body: TypingBody) + suspend fun sendTypingState( + @Path("roomId") roomId: String, + @Path("userId") userId: String, + @Body body: TypingBody + ) /* * Room tagging @@ -352,27 +398,33 @@ internal interface RoomAPI { * Add a tag to a room. */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/rooms/{roomId}/tags/{tag}") - suspend fun putTag(@Path("userId") userId: String, - @Path("roomId") roomId: String, - @Path("tag") tag: String, - @Body body: TagBody) + suspend fun putTag( + @Path("userId") userId: String, + @Path("roomId") roomId: String, + @Path("tag") tag: String, + @Body body: TagBody + ) /** * Delete a tag from a room. */ @DELETE(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/rooms/{roomId}/tags/{tag}") - suspend fun deleteTag(@Path("userId") userId: String, - @Path("roomId") roomId: String, - @Path("tag") tag: String) + suspend fun deleteTag( + @Path("userId") userId: String, + @Path("roomId") roomId: String, + @Path("tag") tag: String + ) /** * Set an AccountData event to the room. */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/rooms/{roomId}/account_data/{type}") - suspend fun setRoomAccountData(@Path("userId") userId: String, - @Path("roomId") roomId: String, - @Path("type") type: String, - @Body content: JsonDict) + suspend fun setRoomAccountData( + @Path("userId") userId: String, + @Path("roomId") roomId: String, + @Path("type") type: String, + @Body content: JsonDict + ) /** * Upgrades the given room to a particular room version. @@ -382,8 +434,10 @@ internal interface RoomAPI { * 403: The user is not permitted to upgrade the room.(M_FORBIDDEN) */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/upgrade") - suspend fun upgradeRoom(@Path("roomId") roomId: String, - @Body body: RoomUpgradeBody): RoomUpgradeResponse + suspend fun upgradeRoom( + @Path("roomId") roomId: String, + @Body body: RoomUpgradeBody + ): RoomUpgradeResponse /** * The API returns the summary of the specified room, if the room could be found and the client should be able to view @@ -392,6 +446,8 @@ internal interface RoomAPI { * https://github.com/deepbluev7/matrix-doc/blob/room-summaries/proposals/3266-room-summary.md */ @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "im.nheko.summary/rooms/{roomIdOrAlias}/summary") - suspend fun getRoomSummary(@Path("roomIdOrAlias") roomidOrAlias: String, - @Query("via") viaServers: List<String>?): RoomStrippedState + suspend fun getRoomSummary( + @Path("roomIdOrAlias") roomidOrAlias: String, + @Query("via") viaServers: List<String>? + ): RoomStrippedState } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAvatarResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAvatarResolver.kt index 29a303475bc17898db0d108dad2498e0de0af3dd..c3d55b267ab812106b008b382fa82e0428c0cde9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAvatarResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAvatarResolver.kt @@ -35,7 +35,7 @@ internal class RoomAvatarResolver @Inject constructor(@UserId private val userId /** * Compute the room avatar url. - * @param realm: the current instance of realm + * @param realm the current instance of realm * @param roomId the roomId of the room to resolve avatar * @return the room avatar url, can be a fallback to a room member avatar or null */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt index 01c4fd1501dba0eb9895409b8d7a8e36f509e7f6..ffe7679575f2a89a5efaac3286469973a0d1459e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt @@ -25,6 +25,7 @@ import org.matrix.android.sdk.internal.session.room.alias.DefaultAliasService import org.matrix.android.sdk.internal.session.room.call.DefaultRoomCallService import org.matrix.android.sdk.internal.session.room.crypto.DefaultRoomCryptoService import org.matrix.android.sdk.internal.session.room.draft.DefaultDraftService +import org.matrix.android.sdk.internal.session.room.location.DefaultLocationSharingService import org.matrix.android.sdk.internal.session.room.membership.DefaultMembershipService import org.matrix.android.sdk.internal.session.room.notification.DefaultRoomPushRuleService import org.matrix.android.sdk.internal.session.room.read.DefaultReadService @@ -69,6 +70,7 @@ internal class DefaultRoomFactory @Inject constructor( private val roomVersionServiceFactory: DefaultRoomVersionService.Factory, private val roomAccountDataServiceFactory: DefaultRoomAccountDataService.Factory, private val viaParameterFinder: ViaParameterFinder, + private val locationSharingServiceFactory: DefaultLocationSharingService.Factory, private val coroutineDispatchers: MatrixCoroutineDispatchers ) : RoomFactory { @@ -96,6 +98,7 @@ internal class DefaultRoomFactory @Inject constructor( roomAccountDataService = roomAccountDataServiceFactory.create(roomId), roomVersionService = roomVersionServiceFactory.create(roomId), viaParameterFinder = viaParameterFinder, + locationSharingService = locationSharingServiceFactory.create(roomId), coroutineDispatchers = coroutineDispatchers ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/DefaultRoomAccountDataService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/DefaultRoomAccountDataService.kt index caeeb3bf5375aeea24618a76028edbe7a61a1d23..aea786b46b4783031f2b7853d877a0f8b8fbad5a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/DefaultRoomAccountDataService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/DefaultRoomAccountDataService.kt @@ -25,9 +25,10 @@ import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataService import org.matrix.android.sdk.api.util.Optional -internal class DefaultRoomAccountDataService @AssistedInject constructor(@Assisted private val roomId: String, - private val dataSource: RoomAccountDataDataSource, - private val updateRoomAccountDataTask: UpdateRoomAccountDataTask +internal class DefaultRoomAccountDataService @AssistedInject constructor( + @Assisted private val roomId: String, + private val dataSource: RoomAccountDataDataSource, + private val updateRoomAccountDataTask: UpdateRoomAccountDataTask ) : RoomAccountDataService { @AssistedFactory diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt index d5a110dfc28993c21e16bb6deb95e5523d6254fb..5196f004ea5431a8a42182fbe080e3c76aedce39 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/accountdata/RoomAccountDataDataSource.kt @@ -33,9 +33,11 @@ import org.matrix.android.sdk.internal.database.model.RoomEntityFields import org.matrix.android.sdk.internal.di.SessionDatabase import javax.inject.Inject -internal class RoomAccountDataDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy, - private val realmSessionProvider: RealmSessionProvider, - private val accountDataMapper: AccountDataMapper) { +internal class RoomAccountDataDataSource @Inject constructor( + @SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider, + private val accountDataMapper: AccountDataMapper +) { fun getAccountDataEvent(roomId: String, type: String): RoomAccountDataEvent? { return getAccountDataEvents(roomId, setOf(type)).firstOrNull() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DeactivateLiveLocationShareWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DeactivateLiveLocationShareWorker.kt new file mode 100644 index 0000000000000000000000000000000000000000..b17753b25a37fdc1d5d7d10cd7a062d097255594 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DeactivateLiveLocationShareWorker.kt @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.aggregation.livelocation + +import android.content.Context +import androidx.work.WorkerParameters +import com.squareup.moshi.JsonClass +import io.realm.RealmConfiguration +import org.matrix.android.sdk.api.util.md5 +import org.matrix.android.sdk.internal.SessionManager +import org.matrix.android.sdk.internal.database.awaitTransaction +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity +import org.matrix.android.sdk.internal.database.query.get +import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.session.SessionComponent +import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker +import org.matrix.android.sdk.internal.worker.SessionWorkerParams +import timber.log.Timber +import javax.inject.Inject + +/** + * Worker dedicated to update live location summary data so that it is considered as deactivated. + * For the context: it is needed since a live location share should be deactivated after a certain timeout. + */ +internal class DeactivateLiveLocationShareWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) : + SessionSafeCoroutineWorker<DeactivateLiveLocationShareWorker.Params>( + context, + params, + sessionManager, + Params::class.java + ) { + + @JsonClass(generateAdapter = true) + internal data class Params( + override val sessionId: String, + override val lastFailureMessage: String? = null, + val eventId: String, + val roomId: String + ) : SessionWorkerParams + + @SessionDatabase + @Inject lateinit var realmConfiguration: RealmConfiguration + + override fun injectWith(injector: SessionComponent) { + injector.inject(this) + } + + override suspend fun doSafeWork(params: Params): Result { + return runCatching { + deactivateLiveLocationShare(params) + }.fold( + onSuccess = { + Result.success() + }, + onFailure = { + Timber.e("failed to deactivate live, eventId: ${params.eventId}, roomId: ${params.roomId}") + Result.failure() + } + ) + } + + private suspend fun deactivateLiveLocationShare(params: Params) { + awaitTransaction(realmConfiguration) { realm -> + Timber.d("deactivating live with id=${params.eventId}") + val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.get( + realm = realm, + roomId = params.roomId, + eventId = params.eventId + ) + aggregatedSummary?.isActive = false + } + } + + override fun buildErrorParams(params: Params, message: String): Params { + return params.copy(lastFailureMessage = params.lastFailureMessage ?: message) + } + + companion object { + fun getWorkName(eventId: String, roomId: String): String { + val hash = "$eventId$roomId".md5() + return "DeactivateLiveLocationWork-$hash" + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt deleted file mode 100644 index 997e31a1091e51b62c75d8086225d60e0346d252..0000000000000000000000000000000000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/DefaultLiveLocationAggregationProcessor.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2022 The Matrix.org Foundation C.I.C. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.matrix.android.sdk.internal.session.room.aggregation.livelocation - -import io.realm.Realm -import org.matrix.android.sdk.api.extensions.orTrue -import org.matrix.android.sdk.api.session.events.model.Event -import org.matrix.android.sdk.api.session.events.model.toContent -import org.matrix.android.sdk.api.session.events.model.toModel -import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent -import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent -import org.matrix.android.sdk.internal.database.mapper.ContentMapper -import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity -import org.matrix.android.sdk.internal.database.query.getOrCreate -import timber.log.Timber -import javax.inject.Inject - -internal class DefaultLiveLocationAggregationProcessor @Inject constructor() : LiveLocationAggregationProcessor { - - override fun handleBeaconInfo(realm: Realm, event: Event, content: MessageBeaconInfoContent, roomId: String, isLocalEcho: Boolean) { - if (event.senderId.isNullOrEmpty() || isLocalEcho) { - return - } - - val targetEventId = if (content.isLive.orTrue()) { - event.eventId - } else { - // when live is set to false, we use the id of the event that should have been replaced - event.unsignedData?.replacesState - } - - if (targetEventId.isNullOrEmpty()) { - Timber.w("no target event id found for the beacon content") - return - } - - val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate( - realm = realm, - roomId = roomId, - eventId = targetEventId - ) - - Timber.d("updating summary of id=$targetEventId with isLive=${content.isLive}") - - aggregatedSummary.endOfLiveTimestampMillis = content.getBestTimestampMillis()?.let { it + (content.timeout ?: 0) } - aggregatedSummary.isActive = content.isLive - } - - override fun handleBeaconLocationData(realm: Realm, event: Event, content: MessageBeaconLocationDataContent, roomId: String, isLocalEcho: Boolean) { - if (event.senderId.isNullOrEmpty() || isLocalEcho) { - return - } - - val targetEventId = content.relatesTo?.eventId - - if (targetEventId.isNullOrEmpty()) { - Timber.w("no target event id found for the live location content") - return - } - - val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate( - realm = realm, - roomId = roomId, - eventId = targetEventId - ) - val updatedLocationTimestamp = content.getBestTimestampMillis() ?: 0 - val currentLocationTimestamp = ContentMapper - .map(aggregatedSummary.lastLocationContent) - .toModel<MessageBeaconLocationDataContent>() - ?.getBestTimestampMillis() - ?: 0 - - if (updatedLocationTimestamp.isMoreRecentThan(currentLocationTimestamp)) { - Timber.d("updating last location of the summary of id=$targetEventId") - aggregatedSummary.lastLocationContent = ContentMapper.map(content.toContent()) - } - } - - private fun Long.isMoreRecentThan(timestamp: Long) = this > timestamp -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt index c0be96f83d6af59a3084055df0bc7b89f6bdccce..05bde8f83f9214beda1bb6d9ac86e83c4000791d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/livelocation/LiveLocationAggregationProcessor.kt @@ -16,25 +16,145 @@ package org.matrix.android.sdk.internal.session.room.aggregation.livelocation +import androidx.work.ExistingWorkPolicy import io.realm.Realm +import org.matrix.android.sdk.api.extensions.orTrue import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent +import org.matrix.android.sdk.internal.database.mapper.ContentMapper +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity +import org.matrix.android.sdk.internal.database.query.findActiveLiveInRoomForUser +import org.matrix.android.sdk.internal.database.query.getOrCreate +import org.matrix.android.sdk.internal.di.SessionId +import org.matrix.android.sdk.internal.di.WorkManagerProvider +import org.matrix.android.sdk.internal.util.time.Clock +import org.matrix.android.sdk.internal.worker.WorkerParamsFactory +import timber.log.Timber +import java.util.concurrent.TimeUnit +import javax.inject.Inject -internal interface LiveLocationAggregationProcessor { - fun handleBeaconInfo( - realm: Realm, - event: Event, - content: MessageBeaconInfoContent, - roomId: String, - isLocalEcho: Boolean, - ) +// TODO add unit tests +internal class LiveLocationAggregationProcessor @Inject constructor( + @SessionId private val sessionId: String, + private val workManagerProvider: WorkManagerProvider, + private val clock: Clock, +) { + + fun handleBeaconInfo(realm: Realm, event: Event, content: MessageBeaconInfoContent, roomId: String, isLocalEcho: Boolean) { + if (event.senderId.isNullOrEmpty() || isLocalEcho) { + return + } + + val isLive = content.isLive.orTrue() + val targetEventId = if (isLive) { + event.eventId + } else { + // when live is set to false, we use the id of the event that should have been replaced + event.unsignedData?.replacesState + } + + if (targetEventId.isNullOrEmpty()) { + Timber.w("no target event id found for the beacon content") + return + } + + val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate( + realm = realm, + roomId = roomId, + eventId = targetEventId + ) + + // remote event can stay with isLive == true while the local summary is no more active + val isActive = aggregatedSummary.isActive.orTrue() && isLive + val endOfLiveTimestampMillis = content.getBestTimestampMillis()?.let { it + (content.timeout ?: 0) } + Timber.d("updating summary of id=$targetEventId with isActive=$isActive and endTimestamp=$endOfLiveTimestampMillis") + + aggregatedSummary.endOfLiveTimestampMillis = endOfLiveTimestampMillis + aggregatedSummary.isActive = isActive + aggregatedSummary.userId = event.senderId + + deactivateAllPreviousBeacons(realm, roomId, event.senderId, targetEventId) + + if (isActive) { + scheduleDeactivationAfterTimeout(targetEventId, roomId, endOfLiveTimestampMillis) + } else { + cancelDeactivationAfterTimeout(targetEventId, roomId) + } + } + + private fun scheduleDeactivationAfterTimeout(eventId: String, roomId: String, endOfLiveTimestampMillis: Long?) { + endOfLiveTimestampMillis ?: return + + val workParams = DeactivateLiveLocationShareWorker.Params(sessionId = sessionId, eventId = eventId, roomId = roomId) + val workData = WorkerParamsFactory.toData(workParams) + val workName = DeactivateLiveLocationShareWorker.getWorkName(eventId = eventId, roomId = roomId) + val workDelayMillis = (endOfLiveTimestampMillis - clock.epochMillis()).coerceAtLeast(0) + Timber.d("scheduling deactivation of $eventId after $workDelayMillis millis") + val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<DeactivateLiveLocationShareWorker>() + .setInitialDelay(workDelayMillis, TimeUnit.MILLISECONDS) + .setInputData(workData) + .build() + + workManagerProvider.workManager.enqueueUniqueWork( + workName, + ExistingWorkPolicy.REPLACE, + workRequest + ) + } + + private fun cancelDeactivationAfterTimeout(eventId: String, roomId: String) { + val workName = DeactivateLiveLocationShareWorker.getWorkName(eventId = eventId, roomId = roomId) + workManagerProvider.workManager.cancelUniqueWork(workName) + } fun handleBeaconLocationData( realm: Realm, event: Event, content: MessageBeaconLocationDataContent, roomId: String, - isLocalEcho: Boolean, - ) + relatedEventId: String?, + isLocalEcho: Boolean + ) { + if (event.senderId.isNullOrEmpty() || isLocalEcho) { + return + } + + if (relatedEventId.isNullOrEmpty()) { + Timber.w("no related event id found for the live location content") + return + } + + val aggregatedSummary = LiveLocationShareAggregatedSummaryEntity.getOrCreate( + realm = realm, + roomId = roomId, + eventId = relatedEventId + ) + val updatedLocationTimestamp = content.getBestTimestampMillis() ?: 0 + val currentLocationTimestamp = ContentMapper + .map(aggregatedSummary.lastLocationContent) + .toModel<MessageBeaconLocationDataContent>() + ?.getBestTimestampMillis() + ?: 0 + + if (updatedLocationTimestamp.isMoreRecentThan(currentLocationTimestamp)) { + Timber.d("updating last location of the summary of id=$relatedEventId") + aggregatedSummary.lastLocationContent = ContentMapper.map(content.toContent()) + } + } + + private fun deactivateAllPreviousBeacons(realm: Realm, roomId: String, userId: String, currentEventId: String) { + LiveLocationShareAggregatedSummaryEntity + .findActiveLiveInRoomForUser( + realm = realm, + roomId = roomId, + userId = userId, + ignoredEventId = currentEventId + ) + .forEach { it.isActive = false } + } + + private fun Long.isMoreRecentThan(timestamp: Long) = this > timestamp } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/DefaultPollAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/DefaultPollAggregationProcessor.kt new file mode 100644 index 0000000000000000000000000000000000000000..90d8e02c3930aead2965618329978d4bf570ae46 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/DefaultPollAggregationProcessor.kt @@ -0,0 +1,205 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.aggregation.poll + +import io.realm.Realm +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.events.model.LocalEcho +import org.matrix.android.sdk.api.session.events.model.RelationType +import org.matrix.android.sdk.api.session.events.model.getRelationContent +import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.getTimelineEvent +import org.matrix.android.sdk.api.session.room.model.PollSummaryContent +import org.matrix.android.sdk.api.session.room.model.VoteInfo +import org.matrix.android.sdk.api.session.room.model.VoteSummary +import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent +import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent +import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent +import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent +import org.matrix.android.sdk.internal.database.mapper.ContentMapper +import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity +import org.matrix.android.sdk.internal.database.model.PollResponseAggregatedSummaryEntity +import org.matrix.android.sdk.internal.database.query.create +import org.matrix.android.sdk.internal.database.query.getOrCreate +import org.matrix.android.sdk.internal.database.query.where +import javax.inject.Inject + +class DefaultPollAggregationProcessor @Inject constructor() : PollAggregationProcessor { + + override fun handlePollStartEvent(realm: Realm, event: Event): Boolean { + val content = event.getClearContent()?.toModel<MessagePollContent>() + if (content?.relatesTo?.type != RelationType.REPLACE) { + return false + } + + val roomId = event.roomId ?: return false + val targetEventId = content.relatesTo.eventId ?: return false + + EventAnnotationsSummaryEntity.getOrCreate(realm, roomId, targetEventId).let { eventAnnotationsSummaryEntity -> + ContentMapper + .map(eventAnnotationsSummaryEntity.pollResponseSummary?.aggregatedContent) + ?.toModel<PollSummaryContent>() + ?.let { existingPollSummaryContent -> + eventAnnotationsSummaryEntity.pollResponseSummary?.aggregatedContent = ContentMapper.map( + PollSummaryContent( + myVote = existingPollSummaryContent.myVote, + votes = emptyList(), + votesSummary = emptyMap(), + totalVotes = 0, + winnerVoteCount = 0, + ) + .toContent() + ) + } + } + return true + } + + override fun handlePollResponseEvent(session: Session, realm: Realm, event: Event): Boolean { + val content = event.getClearContent()?.toModel<MessagePollResponseContent>() ?: return false + val roomId = event.roomId ?: return false + val senderId = event.senderId ?: return false + val targetEventId = (event.getRelationContent() ?: content.relatesTo)?.eventId ?: return false + val targetPollContent = getPollContent(session, roomId, targetEventId) ?: return false + + val annotationsSummaryEntity = getAnnotationsSummaryEntity(realm, roomId, targetEventId) + val aggregatedPollSummaryEntity = getAggregatedPollSummaryEntity(realm, annotationsSummaryEntity) + + val closedTime = aggregatedPollSummaryEntity.closedTime + val responseTime = event.originServerTs ?: return false + if (closedTime != null && responseTime > closedTime) { + return false + } + + if (aggregatedPollSummaryEntity.sourceEvents.contains(event.eventId)) { + return false + } + + val txId = event.unsignedData?.transactionId + val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "") + if (!isLocalEcho && aggregatedPollSummaryEntity.sourceLocalEchoEvents.contains(txId)) { + aggregatedPollSummaryEntity.sourceLocalEchoEvents.remove(txId) + aggregatedPollSummaryEntity.sourceEvents.add(event.eventId) + return false + } + + val vote = content.getBestResponse()?.answers?.first() ?: return false + if (!targetPollContent.getBestPollCreationInfo()?.answers?.map { it.id }?.contains(vote).orFalse()) { + return false + } + + val pollSummaryModel = ContentMapper.map(aggregatedPollSummaryEntity.aggregatedContent).toModel<PollSummaryContent>() + val existingVotes = pollSummaryModel?.votes.orEmpty().toMutableList() + val existingVoteIndex = existingVotes.indexOfFirst { it.userId == senderId } + + if (existingVoteIndex != -1) { + val existingVote = existingVotes[existingVoteIndex] + if (existingVote.voteTimestamp > responseTime) { + return false + } + existingVotes[existingVoteIndex] = VoteInfo(senderId, vote, responseTime) + } else { + existingVotes.add(VoteInfo(senderId, vote, responseTime)) + } + + // Precompute the percentage of votes for all options + val totalVotes = existingVotes.size + val newVotesSummary = existingVotes + .groupBy({ it.option }, { it.userId }) + .mapValues { + VoteSummary( + total = it.value.size, + percentage = if (totalVotes == 0 && it.value.isEmpty()) 0.0 else it.value.size.toDouble() / totalVotes + ) + } + val newWinnerVoteCount = newVotesSummary.maxOf { it.value.total } + + if (isLocalEcho) { + aggregatedPollSummaryEntity.sourceLocalEchoEvents.add(event.eventId) + } else { + aggregatedPollSummaryEntity.sourceEvents.add(event.eventId) + } + + val myVote = existingVotes.find { it.userId == session.myUserId }?.option + + val newSumModel = PollSummaryContent( + myVote = myVote, + votes = existingVotes, + votesSummary = newVotesSummary, + totalVotes = totalVotes, + winnerVoteCount = newWinnerVoteCount + ) + aggregatedPollSummaryEntity.aggregatedContent = ContentMapper.map(newSumModel.toContent()) + + return true + } + + override fun handlePollEndEvent(session: Session, powerLevelsHelper: PowerLevelsHelper, realm: Realm, event: Event): Boolean { + val content = event.getClearContent()?.toModel<MessageEndPollContent>() ?: return false + val roomId = event.roomId ?: return false + val pollEventId = content.relatesTo?.eventId ?: return false + val pollOwnerId = getPollEvent(session, roomId, pollEventId)?.root?.senderId + val isPollOwner = pollOwnerId == event.senderId + + if (!isPollOwner && !powerLevelsHelper.isUserAbleToRedact(event.senderId ?: "")) { + return false + } + + val annotationsSummaryEntity = getAnnotationsSummaryEntity(realm, roomId, pollEventId) + val aggregatedPollSummaryEntity = getAggregatedPollSummaryEntity(realm, annotationsSummaryEntity) + + val txId = event.unsignedData?.transactionId + aggregatedPollSummaryEntity.closedTime = event.originServerTs + + val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "") + if (!isLocalEcho && aggregatedPollSummaryEntity.sourceLocalEchoEvents.contains(txId)) { + aggregatedPollSummaryEntity.sourceLocalEchoEvents.remove(txId) + aggregatedPollSummaryEntity.sourceEvents.add(event.eventId) + } + + return true + } + + private fun getPollEvent(session: Session, roomId: String, eventId: String): TimelineEvent? { + return session.roomService().getRoom(roomId)?.getTimelineEvent(eventId) + } + + private fun getPollContent(session: Session, roomId: String, eventId: String): MessagePollContent? { + val pollEvent = getPollEvent(session, roomId, eventId) + return pollEvent?.getLastMessageContent() as? MessagePollContent + } + + private fun getAnnotationsSummaryEntity(realm: Realm, roomId: String, eventId: String): EventAnnotationsSummaryEntity { + return EventAnnotationsSummaryEntity.where(realm, roomId, eventId).findFirst() + ?: EventAnnotationsSummaryEntity.create(realm, roomId, eventId) + } + + private fun getAggregatedPollSummaryEntity( + realm: Realm, + eventAnnotationsSummaryEntity: EventAnnotationsSummaryEntity + ): PollResponseAggregatedSummaryEntity { + return eventAnnotationsSummaryEntity.pollResponseSummary + ?: realm.createObject(PollResponseAggregatedSummaryEntity::class.java).also { + eventAnnotationsSummaryEntity.pollResponseSummary = it + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollAggregationProcessor.kt new file mode 100644 index 0000000000000000000000000000000000000000..848643b435564a48c2a681009ea2d5ca004bd5db --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollAggregationProcessor.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.aggregation.poll + +import io.realm.Realm +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper + +interface PollAggregationProcessor { + /** + * Poll start events don't need to be processed by the aggregator. + * This function will only handle if the poll is edited and will update the poll summary entity. + * Returns true if the event is aggregated. + */ + fun handlePollStartEvent( + realm: Realm, + event: Event + ): Boolean + + /** + * Aggregates poll response event after many conditional checks like if the poll is ended, if the user is changing his/her vote etc. + * Returns true if the event is aggregated. + */ + fun handlePollResponseEvent( + session: Session, + realm: Realm, + event: Event + ): Boolean + + /** + * Updates poll summary entity and mark it is ended after many conditional checks like if the poll is already ended etc. + * Returns true if the event is aggregated. + */ + fun handlePollEndEvent( + session: Session, + powerLevelsHelper: PowerLevelsHelper, + realm: Realm, + event: Event + ): Boolean +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt index 7c137a810275a1146ecb6ea5fa6e6a3531ed1713..fa19b4f9cfdd450c48b417e202ef43331bad7b42 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/alias/RoomAliasAvailabilityChecker.kt @@ -16,7 +16,7 @@ package org.matrix.android.sdk.internal.session.room.alias -import org.matrix.android.sdk.api.MatrixPatterns.getDomain +import org.matrix.android.sdk.api.MatrixPatterns.getServerName import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.room.alias.RoomAliasError import org.matrix.android.sdk.internal.di.UserId @@ -65,6 +65,6 @@ internal class RoomAliasAvailabilityChecker @Inject constructor( } companion object { - internal fun String.toFullLocalAlias(userId: String) = "#" + this + ":" + userId.getDomain() + internal fun String.toFullLocalAlias(userId: String) = "#" + this + ":" + userId.getServerName() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/crypto/DefaultRoomCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/crypto/DefaultRoomCryptoService.kt index 2546c58cc7c64974d3b3a5b921651fc1614ea435..4f0228e6a8850445fd14ebba547e2507dfb99b8f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/crypto/DefaultRoomCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/crypto/DefaultRoomCryptoService.kt @@ -61,10 +61,10 @@ internal class DefaultRoomCryptoService @AssistedInject constructor( (!force && isEncrypted() && encryptionAlgorithm() == MXCRYPTO_ALGORITHM_MEGOLM) -> { throw IllegalStateException("Encryption is already enabled for this room") } - (!force && algorithm != MXCRYPTO_ALGORITHM_MEGOLM) -> { + (!force && algorithm != MXCRYPTO_ALGORITHM_MEGOLM) -> { throw InvalidParameterException("Only MXCRYPTO_ALGORITHM_MEGOLM algorithm is supported") } - else -> { + else -> { val params = SendStateTask.Params( roomId = roomId, stateKey = "", diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt index 3867e0dc8d3fe6cd589f115593385e46875d31d3..1ea8addb20c113cfb2d745ffd0a6d7702e3213e7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt @@ -26,9 +26,10 @@ import org.matrix.android.sdk.api.session.room.send.DraftService import org.matrix.android.sdk.api.session.room.send.UserDraft import org.matrix.android.sdk.api.util.Optional -internal class DefaultDraftService @AssistedInject constructor(@Assisted private val roomId: String, - private val draftRepository: DraftRepository, - private val coroutineDispatchers: MatrixCoroutineDispatchers +internal class DefaultDraftService @AssistedInject constructor( + @Assisted private val roomId: String, + private val draftRepository: DraftRepository, + private val coroutineDispatchers: MatrixCoroutineDispatchers ) : DraftService { @AssistedFactory diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DraftRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DraftRepository.kt index c8c52c4b23553aaf9a00c5f4e8c1e93dc36ae429..b672ef7e46ec1d0ba5f93377f1661431050d0dda 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DraftRepository.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DraftRepository.kt @@ -35,8 +35,10 @@ import org.matrix.android.sdk.internal.util.awaitTransaction import timber.log.Timber import javax.inject.Inject -internal class DraftRepository @Inject constructor(@SessionDatabase private val monarchy: Monarchy, - private val realmSessionProvider: RealmSessionProvider) { +internal class DraftRepository @Inject constructor( + @SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider +) { suspend fun saveDraft(roomId: String, userDraft: UserDraft) { monarchy.awaitTransaction { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/DefaultLocationSharingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/DefaultLocationSharingService.kt new file mode 100644 index 0000000000000000000000000000000000000000..8cf6fcdfbf4e43389e62f2165e35157555e96b69 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/DefaultLocationSharingService.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.location + +import androidx.lifecycle.LiveData +import com.zhuinden.monarchy.Monarchy +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import org.matrix.android.sdk.api.session.room.location.LocationSharingService +import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary +import org.matrix.android.sdk.internal.database.mapper.LiveLocationShareAggregatedSummaryMapper +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity +import org.matrix.android.sdk.internal.database.query.findRunningLiveInRoom +import org.matrix.android.sdk.internal.di.SessionDatabase + +// TODO add unit tests +internal class DefaultLocationSharingService @AssistedInject constructor( + @Assisted private val roomId: String, + @SessionDatabase private val monarchy: Monarchy, + private val liveLocationShareAggregatedSummaryMapper: LiveLocationShareAggregatedSummaryMapper, +) : LocationSharingService { + + @AssistedFactory + interface Factory { + fun create(roomId: String): DefaultLocationSharingService + } + + override fun getRunningLiveLocationShareSummaries(): LiveData<List<LiveLocationShareAggregatedSummary>> { + return monarchy.findAllMappedWithChanges( + { LiveLocationShareAggregatedSummaryEntity.findRunningLiveInRoom(it, roomId = roomId) }, + { liveLocationShareAggregatedSummaryMapper.map(it) } + ) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt index d3d1cb856a05e970a85ac891dbc730058d1f9475..15d0889255155dadf49bbae7c156d9ccc4a551e1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/LoadRoomMembersTask.kt @@ -68,9 +68,9 @@ internal class DefaultLoadRoomMembersTask @Inject constructor( override suspend fun execute(params: LoadRoomMembersTask.Params) { when (getRoomMembersLoadStatus(params.roomId)) { - RoomMembersLoadStatusType.NONE -> doRequest(params) + RoomMembersLoadStatusType.NONE -> doRequest(params) RoomMembersLoadStatusType.LOADING -> waitPreviousRequestToFinish(params) - RoomMembersLoadStatusType.LOADED -> Unit + RoomMembersLoadStatusType.LOADED -> Unit } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomChangeMembershipStateDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomChangeMembershipStateDataSource.kt index 35d8cb08af62e62a75b796ce158b251c033c373e..c61625b2b1845fb46fc39ae779d1259c8ebb3af4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomChangeMembershipStateDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomChangeMembershipStateDataSource.kt @@ -61,8 +61,8 @@ internal class RoomChangeMembershipStateDataSource @Inject constructor() { private fun Membership.toMembershipChangeState(): ChangeMembershipState { return when { this == Membership.JOIN -> ChangeMembershipState.Joined - this.isLeft() -> ChangeMembershipState.Left - else -> ChangeMembershipState.Unknown + this.isLeft() -> ChangeMembershipState.Left + else -> ChangeMembershipState.Unknown } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt index 59e0f81ece88e81435d1c866b77f492d27782104..4645bb05ab38bc5cd41de8c3d5be93fa11bfd274 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt @@ -52,8 +52,8 @@ internal class RoomDisplayNameResolver @Inject constructor( /** * Compute the room display name. * - * @param realm: the current instance of realm - * @param roomId: the roomId to resolve the name of. + * @param realm the current instance of realm + * @param roomId the roomId to resolve the name of. * @return the room display name */ fun resolve(realm: Realm, roomId: String): RoomName { @@ -110,32 +110,32 @@ internal class RoomDisplayNameResolver @Inject constructor( } val otherMembersCount = otherMembersSubset.count() name = when (otherMembersCount) { - 0 -> { + 0 -> { // Get left members if any val leftMembersNames = roomMembers.queryLeftRoomMembersEvent() .findAll() .map { displayNameResolver.getBestName(it.toMatrixItem()) } roomDisplayNameFallbackProvider.getNameForEmptyRoom(roomSummary?.isDirect.orFalse(), leftMembersNames) } - 1 -> { + 1 -> { roomDisplayNameFallbackProvider.getNameFor1member( resolveRoomMemberName(otherMembersSubset[0], roomMembers) ) } - 2 -> { + 2 -> { roomDisplayNameFallbackProvider.getNameFor2members( resolveRoomMemberName(otherMembersSubset[0], roomMembers), resolveRoomMemberName(otherMembersSubset[1], roomMembers) ) } - 3 -> { + 3 -> { roomDisplayNameFallbackProvider.getNameFor3members( resolveRoomMemberName(otherMembersSubset[0], roomMembers), resolveRoomMemberName(otherMembersSubset[1], roomMembers), resolveRoomMemberName(otherMembersSubset[2], roomMembers) ) } - 4 -> { + 4 -> { roomDisplayNameFallbackProvider.getNameFor4members( resolveRoomMemberName(otherMembersSubset[0], roomMembers), resolveRoomMemberName(otherMembersSubset[1], roomMembers), @@ -158,8 +158,10 @@ internal class RoomDisplayNameResolver @Inject constructor( } /** See [org.matrix.android.sdk.api.session.room.sender.SenderInfo.disambiguatedDisplayName]. */ - private fun resolveRoomMemberName(roomMemberSummary: RoomMemberSummaryEntity, - roomMemberHelper: RoomMemberHelper): String { + private fun resolveRoomMemberName( + roomMemberSummary: RoomMemberSummaryEntity, + roomMemberHelper: RoomMemberHelper + ): String { val isUnique = roomMemberHelper.isUniqueDisplayName(roomMemberSummary.displayName) return if (isUnique) { displayNameResolver.getBestName(roomMemberSummary.toMatrixItem()) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt index a1b30a0be562756ebec3d617f9e3b9119ad02305..1e36e9c6da52a350429d74038a7be2d9f6623cdf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt @@ -34,11 +34,13 @@ internal class RoomMemberEventHandler @Inject constructor( @UserId private val myUserId: String ) { - fun handle(realm: Realm, - roomId: String, - event: Event, - isInitialSync: Boolean, - aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean { + fun handle( + realm: Realm, + roomId: String, + event: Event, + isInitialSync: Boolean, + aggregator: SyncResponsePostTreatmentAggregator? = null + ): Boolean { if (event.type != EventType.STATE_ROOM_MEMBER) { return false } @@ -59,12 +61,14 @@ internal class RoomMemberEventHandler @Inject constructor( } } - private fun handleInitialSync(realm: Realm, - roomId: String, - currentUserId: String, - eventUserId: String, - roomMember: RoomMemberContent, - aggregator: SyncResponsePostTreatmentAggregator?): Boolean { + private fun handleInitialSync( + realm: Realm, + roomId: String, + currentUserId: String, + eventUserId: String, + roomMember: RoomMemberContent, + aggregator: SyncResponsePostTreatmentAggregator? + ): Boolean { if (currentUserId != eventUserId) { saveUserEntityLocallyIfNecessary(realm, eventUserId, roomMember) } @@ -73,10 +77,12 @@ internal class RoomMemberEventHandler @Inject constructor( return true } - private fun saveRoomMemberEntityLocally(realm: Realm, - roomId: String, - userId: String, - roomMember: RoomMemberContent) { + private fun saveRoomMemberEntityLocally( + realm: Realm, + roomId: String, + userId: String, + roomMember: RoomMemberContent + ) { val roomMemberEntity = RoomMemberEntityFactory.create( roomId, userId, @@ -96,9 +102,11 @@ internal class RoomMemberEventHandler @Inject constructor( return RoomMemberSummaryEntity.where(realm, roomId, userId).findFirst()?.userPresenceEntity } - private fun saveUserEntityLocallyIfNecessary(realm: Realm, - userId: String, - roomMember: RoomMemberContent) { + private fun saveUserEntityLocallyIfNecessary( + realm: Realm, + userId: String, + roomMember: RoomMemberContent + ) { if (roomMember.membership.isActive()) { saveUserLocally(realm, userId, roomMember) } @@ -109,9 +117,11 @@ internal class RoomMemberEventHandler @Inject constructor( realm.insertOrUpdate(userEntity) } - private fun updateDirectChatsIfNecessary(roomId: String, - roomMember: RoomMemberContent, - aggregator: SyncResponsePostTreatmentAggregator?) { + private fun updateDirectChatsIfNecessary( + roomId: String, + roomMember: RoomMemberContent, + aggregator: SyncResponsePostTreatmentAggregator? + ) { // check whether this new room member event may be used to update the directs dictionary in account data // this is required to handle correctly invite by email in DM val mxId = roomMember.thirdPartyInvite?.signed?.mxid @@ -120,12 +130,14 @@ internal class RoomMemberEventHandler @Inject constructor( } } - private fun handleIncrementalSync(realm: Realm, - roomId: String, - eventUserId: String, - roomMember: RoomMemberContent, - prevContent: Content?, - aggregator: SyncResponsePostTreatmentAggregator?): Boolean { + private fun handleIncrementalSync( + realm: Realm, + roomId: String, + eventUserId: String, + roomMember: RoomMemberContent, + prevContent: Content?, + aggregator: SyncResponsePostTreatmentAggregator? + ): Boolean { if (aggregator != null) { val previousDisplayName = prevContent?.get("displayname") as? String val previousAvatar = prevContent?.get("avatar_url") as? String diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberHelper.kt index 40228fe8c977a1f4372b6dca04d23ed02cde8a59..7da12a75de58a111c0cb82b6a064f3fbea06e9cc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberHelper.kt @@ -33,8 +33,9 @@ import org.matrix.android.sdk.internal.database.query.where * It allows to get the live membership of a user. */ -internal class RoomMemberHelper(private val realm: Realm, - private val roomId: String +internal class RoomMemberHelper( + private val realm: Realm, + private val roomId: String ) { private val roomSummary: RoomSummaryEntity? by lazy { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/admin/MembershipAdminTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/admin/MembershipAdminTask.kt index d2c21f352038aff9cbc9c0fff3ab87a18769719a..b07a77a18fcc24ef1b556c1f32a0a074647079e6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/admin/MembershipAdminTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/admin/MembershipAdminTask.kt @@ -43,9 +43,9 @@ internal class DefaultMembershipAdminTask @Inject constructor(private val roomAP val userIdAndReason = UserIdAndReason(params.userId, params.reason) executeRequest(null) { when (params.type) { - MembershipAdminTask.Type.BAN -> roomAPI.ban(params.roomId, userIdAndReason) + MembershipAdminTask.Type.BAN -> roomAPI.ban(params.roomId, userIdAndReason) MembershipAdminTask.Type.UNBAN -> roomAPI.unban(params.roomId, userIdAndReason) - MembershipAdminTask.Type.KICK -> roomAPI.kick(params.roomId, userIdAndReason) + MembershipAdminTask.Type.KICK -> roomAPI.kick(params.roomId, userIdAndReason) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt index 85f53e13469ebc527500e24f6bf47dad8a8df37c..d46100a3a82eca96110544bb565bec438034b4bf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/DefaultRoomPushRuleService.kt @@ -29,9 +29,11 @@ import org.matrix.android.sdk.internal.database.model.PushRuleEntity import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase -internal class DefaultRoomPushRuleService @AssistedInject constructor(@Assisted private val roomId: String, - private val setRoomNotificationStateTask: SetRoomNotificationStateTask, - @SessionDatabase private val monarchy: Monarchy) : +internal class DefaultRoomPushRuleService @AssistedInject constructor( + @Assisted private val roomId: String, + private val setRoomNotificationStateTask: SetRoomNotificationStateTask, + @SessionDatabase private val monarchy: Monarchy +) : RoomPushRuleService { @AssistedFactory diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt index a5a5ab58ba1736718094dd9e340904b1921351df..42b069f8fa3c120daf29fc3279058c3bfdfe553f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt @@ -33,10 +33,10 @@ internal fun PushRuleEntity.toRoomPushRule(): RoomPushRule? { RuleSetKey.OVERRIDE -> { PushRulesMapper.map(this) } - RuleSetKey.ROOM -> { + RuleSetKey.ROOM -> { PushRulesMapper.mapRoomRule(this) } - else -> null + else -> null } return if (pushRule == null || kind == null) { null @@ -47,7 +47,7 @@ internal fun PushRuleEntity.toRoomPushRule(): RoomPushRule? { internal fun RoomNotificationState.toRoomPushRule(roomId: String): RoomPushRule? { return when { - this == RoomNotificationState.ALL_MESSAGES -> null + this == RoomNotificationState.ALL_MESSAGES -> null this == RoomNotificationState.ALL_MESSAGES_NOISY -> { val rule = PushRule( actions = listOf(Action.Notify, Action.Sound()).toJson(), @@ -56,7 +56,7 @@ internal fun RoomNotificationState.toRoomPushRule(roomId: String): RoomPushRule? ) return RoomPushRule(RuleSetKey.ROOM, rule) } - else -> { + else -> { val condition = PushCondition( kind = Kind.EventMatch.value, key = "room_id", diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/SetRoomNotificationStateTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/SetRoomNotificationStateTask.kt index 021d7dbefb104ce7734f3b5fc2f2d2d83139ce91..3d51d19cba5372559226bac78d62e4c3509f8fb9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/SetRoomNotificationStateTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/SetRoomNotificationStateTask.kt @@ -35,9 +35,11 @@ internal interface SetRoomNotificationStateTask : Task<SetRoomNotificationStateT ) } -internal class DefaultSetRoomNotificationStateTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy, - private val removePushRuleTask: RemovePushRuleTask, - private val addPushRuleTask: AddPushRuleTask) : +internal class DefaultSetRoomNotificationStateTask @Inject constructor( + @SessionDatabase private val monarchy: Monarchy, + private val removePushRuleTask: RemovePushRuleTask, + private val addPushRuleTask: AddPushRuleTask +) : SetRoomNotificationStateTask { override suspend fun execute(params: SetRoomNotificationStateTask.Params) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt index 63fc26e9d6d8e502b95f68155fb573b3860e1ec2..55c7bb1ddf6fa230166b2546348ce99843f033f0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/peeking/PeekRoomTask.kt @@ -111,7 +111,7 @@ internal class DefaultPeekRoomTask @Inject constructor( )) }?.chunk?.firstOrNull { it.roomId == roomId } } - else -> { + else -> { // RoomDirectoryVisibility.PRIVATE or null // We cannot resolve this room :/ null diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/prune/RedactionEventProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/prune/RedactionEventProcessor.kt index e926d6a785ab1b859508f5310fe50091fb5c2722..e33fbb56b19d72b3124d880c6dd15cb9ede3b0a3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/prune/RedactionEventProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/prune/RedactionEventProcessor.kt @@ -145,10 +145,10 @@ internal class RedactionEventProcessor @Inject constructor() : EventInsertLivePr private fun computeAllowedKeys(type: String): List<String> { // Add filtered content, allowed keys in content depends on the event type return when (type) { - EventType.STATE_ROOM_MEMBER -> listOf("membership") - EventType.STATE_ROOM_CREATE -> listOf("creator") - EventType.STATE_ROOM_JOIN_RULES -> listOf("join_rule") - EventType.STATE_ROOM_POWER_LEVELS -> listOf( + EventType.STATE_ROOM_MEMBER -> listOf("membership") + EventType.STATE_ROOM_CREATE -> listOf("creator") + EventType.STATE_ROOM_JOIN_RULES -> listOf("join_rule") + EventType.STATE_ROOM_POWER_LEVELS -> listOf( "users", "users_default", "events", @@ -159,10 +159,10 @@ internal class RedactionEventProcessor @Inject constructor() : EventInsertLivePr "redact", "invite" ) - EventType.STATE_ROOM_ALIASES -> listOf("aliases") + EventType.STATE_ROOM_ALIASES -> listOf("aliases") EventType.STATE_ROOM_CANONICAL_ALIAS -> listOf("alias") - EventType.FEEDBACK -> listOf("type", "target_event_id") - else -> emptyList() + EventType.FEEDBACK -> listOf("type", "target_event_id") + else -> emptyList() } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt index 7b68e2a74c1b3b1efe728301bb65f4fcdcee05e9..9839a44427fcd5939e80ab13a8753528052ab85b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt @@ -92,25 +92,31 @@ internal class DefaultRelationService @AssistedInject constructor( } } - override fun editPoll(targetEvent: TimelineEvent, - pollType: PollType, - question: String, - options: List<String>): Cancelable { + override fun editPoll( + targetEvent: TimelineEvent, + pollType: PollType, + question: String, + options: List<String> + ): Cancelable { return eventEditor.editPoll(targetEvent, pollType, question, options) } - override fun editTextMessage(targetEvent: TimelineEvent, - msgType: String, - newBodyText: CharSequence, - newBodyAutoMarkdown: Boolean, - compatibilityBodyText: String): Cancelable { + override fun editTextMessage( + targetEvent: TimelineEvent, + msgType: String, + newBodyText: CharSequence, + newBodyAutoMarkdown: Boolean, + compatibilityBodyText: String + ): Cancelable { return eventEditor.editTextMessage(targetEvent, msgType, newBodyText, newBodyAutoMarkdown, compatibilityBodyText) } - override fun editReply(replyToEdit: TimelineEvent, - originalTimelineEvent: TimelineEvent, - newBodyText: String, - compatibilityBodyText: String): Cancelable { + override fun editReply( + replyToEdit: TimelineEvent, + originalTimelineEvent: TimelineEvent, + newBodyText: String, + compatibilityBodyText: String + ): Cancelable { return eventEditor.editReply(replyToEdit, originalTimelineEvent, newBodyText, compatibilityBodyText) } @@ -164,7 +170,8 @@ internal class DefaultRelationService @AssistedInject constructor( msgType: String, autoMarkdown: Boolean, formattedText: String?, - eventReplied: TimelineEvent?): Cancelable? { + eventReplied: TimelineEvent? + ): Cancelable? { val event = if (eventReplied != null) { // Reply within a thread eventFactory.createReplyTextEvent( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt index 7bf7d6b587584285cdfc697337b9730c7f424377..795e9003ce6baaaed8b3c21fe6b04fc79926e613 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/EventEditor.kt @@ -38,11 +38,13 @@ internal class EventEditor @Inject constructor( private val clock: Clock, ) { - fun editTextMessage(targetEvent: TimelineEvent, - msgType: String, - newBodyText: CharSequence, - newBodyAutoMarkdown: Boolean, - compatibilityBodyText: String): Cancelable { + fun editTextMessage( + targetEvent: TimelineEvent, + msgType: String, + newBodyText: CharSequence, + newBodyAutoMarkdown: Boolean, + compatibilityBodyText: String + ): Cancelable { val roomId = targetEvent.roomId if (targetEvent.root.sendState.hasFailed()) { // We create a new in memory event for the EventSenderProcessor but we keep the eventId of the failed event. @@ -61,10 +63,12 @@ internal class EventEditor @Inject constructor( } } - fun editPoll(targetEvent: TimelineEvent, - pollType: PollType, - question: String, - options: List<String>): Cancelable { + fun editPoll( + targetEvent: TimelineEvent, + pollType: PollType, + question: String, + options: List<String> + ): Cancelable { val roomId = targetEvent.roomId if (targetEvent.root.sendState.hasFailed()) { val editedEvent = eventFactory.createPollEvent(roomId, pollType, question, options).copy( @@ -92,10 +96,12 @@ internal class EventEditor @Inject constructor( return eventSenderProcessor.postEvent(editedEvent) } - fun editReply(replyToEdit: TimelineEvent, - originalTimelineEvent: TimelineEvent, - newBodyText: String, - compatibilityBodyText: String): Cancelable { + fun editReply( + replyToEdit: TimelineEvent, + originalTimelineEvent: TimelineEvent, + newBodyText: String, + compatibilityBodyText: String + ): Cancelable { val roomId = replyToEdit.roomId if (replyToEdit.root.sendState.hasFailed()) { // We create a new in memory event for the EventSenderProcessor but we keep the eventId of the failed event. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FindReactionEventForUndoTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FindReactionEventForUndoTask.kt index f7cfa3489d347ae28325292728db2aef24002eef..585f896f32f2d3d0f8b01e78d81788975bf18f0f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FindReactionEventForUndoTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FindReactionEventForUndoTask.kt @@ -41,7 +41,8 @@ internal interface FindReactionEventForUndoTask : Task<FindReactionEventForUndoT internal class DefaultFindReactionEventForUndoTask @Inject constructor( @SessionDatabase private val monarchy: Monarchy, - @UserId private val userId: String) : FindReactionEventForUndoTask { + @UserId private val userId: String +) : FindReactionEventForUndoTask { override suspend fun execute(params: FindReactionEventForUndoTask.Params): FindReactionEventForUndoTask.Result { val eventId = Realm.getInstance(monarchy.realmConfiguration).use { realm -> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/UpdateQuickReactionTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/UpdateQuickReactionTask.kt index d0ab430dad7adf7649fa311f4894b3a9a515d491..24e8ba7f9e51d7fe33376559dd9fdf154e019355 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/UpdateQuickReactionTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/UpdateQuickReactionTask.kt @@ -41,8 +41,10 @@ internal interface UpdateQuickReactionTask : Task<UpdateQuickReactionTask.Params ) } -internal class DefaultUpdateQuickReactionTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy, - @UserId private val userId: String) : UpdateQuickReactionTask { +internal class DefaultUpdateQuickReactionTask @Inject constructor( + @SessionDatabase private val monarchy: Monarchy, + @UserId private val userId: String +) : UpdateQuickReactionTask { override suspend fun execute(params: UpdateQuickReactionTask.Params): UpdateQuickReactionTask.Result { var res: Pair<String?, List<String>?>? = null diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadSummariesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadSummariesTask.kt index c5f9bd13fd59b889ea18b5e2ab6597a63a22d6df..254dee42959c6e5770888c1cea61e1066a1a03df 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadSummariesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadSummariesTask.kt @@ -77,8 +77,10 @@ internal class DefaultFetchThreadSummariesTask @Inject constructor( return handleResponse(response, params) } - private suspend fun handleResponse(response: PaginationResponse, - params: FetchThreadSummariesTask.Params): Result { + private suspend fun handleResponse( + response: PaginationResponse, + params: FetchThreadSummariesTask.Params + ): Result { val rootThreadList = response.events monarchy.awaitTransaction { realm -> val roomEntity = RoomEntity.where(realm, roomId = params.roomId).findFirst() ?: return@awaitTransaction diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt index dabdd04f60205d9e3b0c986489817e043d92c036..bad734173e84c33455141c27db2111549b3a738a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt @@ -109,8 +109,10 @@ internal class DefaultFetchThreadTimelineTask @Inject constructor( return handleRelationsResponse(response, params) } - private suspend fun handleRelationsResponse(response: RelationsResponse, - params: FetchThreadTimelineTask.Params): Result { + private suspend fun handleRelationsResponse( + response: RelationsResponse, + params: FetchThreadTimelineTask.Params + ): Result { val threadList = response.chunks val threadRootEvent = response.originalEvent val hasReachEnd = response.nextBatch == null @@ -232,9 +234,11 @@ internal class DefaultFetchThreadTimelineTask @Inject constructor( } } - private fun handleReaction(realm: Realm, - event: Event, - roomId: String) { + private fun handleReaction( + realm: Realm, + event: Event, + roomId: String + ) { val unsignedData = event.unsignedData ?: return val relatedEventId = event.eventId ?: return diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomChildRelationInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomChildRelationInfo.kt index 5bad334afc1922ecb815fddb5e5b6a17a47116aa..fffca96acf347ab0552accd40a7110b56d27a209 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomChildRelationInfo.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relationship/RoomChildRelationInfo.kt @@ -43,7 +43,6 @@ internal class RoomChildRelationInfo( data class SpaceChildInfo( val roomId: String, val order: String?, -// val autoJoin: Boolean, val viaServers: List<String> ) @@ -60,18 +59,13 @@ internal class RoomChildRelationInfo( fun getDirectChildrenDescriptions(): List<SpaceChildInfo> { return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_CHILD) .findAll() -// .also { -// Timber.v("## Space: Found ${it.count()} m.space.child state events for $roomId") -// } .mapNotNull { ContentMapper.map(it.root?.content).toModel<SpaceChildContent>()?.let { scc -> -// Timber.v("## Space child desc state event $scc") // Children where via is not present are ignored. scc.via?.let { via -> SpaceChildInfo( roomId = it.stateKey, order = scc.validOrder(), -// autoJoin = scc.autoJoin ?: false, viaServers = via ) } @@ -83,17 +77,13 @@ internal class RoomChildRelationInfo( fun getParentDescriptions(): List<SpaceParentInfo> { return CurrentStateEventEntity.whereType(realm, roomId, EventType.STATE_SPACE_PARENT) .findAll() -// .also { -// Timber.v("## Space: Found ${it.count()} m.space.parent state events for $roomId") -// } .mapNotNull { - ContentMapper.map(it.root?.content).toModel<SpaceParentContent>()?.let { scc -> -// Timber.v("## Space parent desc state event $scc") + ContentMapper.map(it.root?.content).toModel<SpaceParentContent>()?.let { spaceParentContent -> // Parent where via is not present are ignored. - scc.via?.let { via -> + spaceParentContent.via?.let { via -> SpaceParentInfo( roomId = it.stateKey, - canonical = scc.canonical ?: false, + canonical = spaceParentContent.canonical ?: false, viaServers = via, stateEventSender = it.root?.sender ?: "" ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/DefaultReportingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/DefaultReportingService.kt index c961f718ef658ea8566cea42c36ea449f034cdcb..1e32bf5e16ffa0cf611704d25f268ef1b14a2348 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/DefaultReportingService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/reporting/DefaultReportingService.kt @@ -21,8 +21,9 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import org.matrix.android.sdk.api.session.room.reporting.ReportingService -internal class DefaultReportingService @AssistedInject constructor(@Assisted private val roomId: String, - private val reportContentTask: ReportContentTask +internal class DefaultReportingService @AssistedInject constructor( + @Assisted private val roomId: String, + private val reportContentTask: ReportContentTask ) : ReportingService { @AssistedFactory diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt index 8529365858e6bbaeaf34b4b1070ca18645287cde..fc78abcfd93bd355147e81fd847167c8ce87cb67 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt @@ -198,7 +198,7 @@ internal class DefaultSendService @AssistedInject constructor( localEchoRepository.updateSendState(localEcho.eventId, roomId, SendState.UNSENT) internalSendMedia(listOf(localEcho.root), attachmentData, true) } - is MessageFileContent -> { + is MessageFileContent -> { val attachmentData = ContentAttachmentData( size = messageContent.info!!.size, mimeType = messageContent.mimeType, @@ -222,7 +222,7 @@ internal class DefaultSendService @AssistedInject constructor( localEchoRepository.updateSendState(localEcho.eventId, roomId, SendState.UNSENT) internalSendMedia(listOf(localEcho.root), attachmentData, true) } - else -> NoOpCancellable + else -> NoOpCancellable } } return NoOpCancellable @@ -265,10 +265,11 @@ internal class DefaultSendService @AssistedInject constructor( } } - override fun sendMedias(attachments: List<ContentAttachmentData>, - compressBeforeSending: Boolean, - roomIds: Set<String>, - rootThreadEventId: String? + override fun sendMedias( + attachments: List<ContentAttachmentData>, + compressBeforeSending: Boolean, + roomIds: Set<String>, + rootThreadEventId: String? ): Cancelable { return attachments.mapTo(CancelableBag()) { sendMedia( @@ -280,10 +281,11 @@ internal class DefaultSendService @AssistedInject constructor( } } - override fun sendMedia(attachment: ContentAttachmentData, - compressBeforeSending: Boolean, - roomIds: Set<String>, - rootThreadEventId: String? + override fun sendMedia( + attachment: ContentAttachmentData, + compressBeforeSending: Boolean, + roomIds: Set<String>, + rootThreadEventId: String? ): Cancelable { // Ensure that the event will not be send in a thread if we are a different flow. // Like sending files to multiple rooms @@ -354,10 +356,12 @@ internal class DefaultSendService @AssistedInject constructor( return "${roomId}_$identifier" } - private fun createUploadMediaWork(allLocalEchos: List<Event>, - attachment: ContentAttachmentData, - isRoomEncrypted: Boolean, - compressBeforeSending: Boolean): OneTimeWorkRequest { + private fun createUploadMediaWork( + allLocalEchos: List<Event>, + attachment: ContentAttachmentData, + isRoomEncrypted: Boolean, + compressBeforeSending: Boolean + ): OneTimeWorkRequest { val localEchoIds = allLocalEchos.map { LocalEchoIdentifiers(it.roomId!!, it.eventId!!) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt index d39088bd6dc54758b7449d1880b481504b89afbe..3b9ca44d18cb34826a2f5ed9518c5a74a3c94674 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt @@ -119,12 +119,14 @@ internal class LocalEchoEventFactory @Inject constructor( return createMessageEvent(roomId, textContent.toMessageTextContent(msgType)) } - fun createReplaceTextEvent(roomId: String, - targetEventId: String, - newBodyText: CharSequence, - newBodyAutoMarkdown: Boolean, - msgType: String, - compatibilityText: String): Event { + fun createReplaceTextEvent( + roomId: String, + targetEventId: String, + newBodyText: CharSequence, + newBodyAutoMarkdown: Boolean, + msgType: String, + compatibilityText: String + ): Event { return createMessageEvent( roomId, MessageTextContent( @@ -138,9 +140,11 @@ internal class LocalEchoEventFactory @Inject constructor( ) } - private fun createPollContent(question: String, - options: List<String>, - pollType: PollType): MessagePollContent { + private fun createPollContent( + question: String, + options: List<String>, + pollType: PollType + ): MessagePollContent { return MessagePollContent( unstablePollCreationInfo = PollCreationInfo( question = PollQuestion(unstableQuestion = question), @@ -152,11 +156,13 @@ internal class LocalEchoEventFactory @Inject constructor( ) } - fun createPollReplaceEvent(roomId: String, - pollType: PollType, - targetEventId: String, - question: String, - options: List<String>): Event { + fun createPollReplaceEvent( + roomId: String, + pollType: PollType, + targetEventId: String, + question: String, + options: List<String> + ): Event { val newContent = MessagePollContent( relatesTo = RelationDefaultContent(RelationType.REPLACE, targetEventId), newContent = createPollContent(question, options, pollType).toContent() @@ -172,9 +178,11 @@ internal class LocalEchoEventFactory @Inject constructor( ) } - fun createPollReplyEvent(roomId: String, - pollEventId: String, - answerId: String): Event { + fun createPollReplyEvent( + roomId: String, + pollEventId: String, + answerId: String + ): Event { val content = MessagePollResponseContent( body = answerId, relatesTo = RelationDefaultContent( @@ -195,10 +203,12 @@ internal class LocalEchoEventFactory @Inject constructor( ) } - fun createPollEvent(roomId: String, - pollType: PollType, - question: String, - options: List<String>): Event { + fun createPollEvent( + roomId: String, + pollType: PollType, + question: String, + options: List<String> + ): Event { val content = createPollContent(question, options, pollType) val localId = LocalEcho.createLocalEchoId() return Event( @@ -212,8 +222,10 @@ internal class LocalEchoEventFactory @Inject constructor( ) } - fun createEndPollEvent(roomId: String, - eventId: String): Event { + fun createEndPollEvent( + roomId: String, + eventId: String + ): Event { val content = MessageEndPollContent( relatesTo = RelationDefaultContent( type = RelationType.REFERENCE, @@ -232,11 +244,13 @@ internal class LocalEchoEventFactory @Inject constructor( ) } - fun createLocationEvent(roomId: String, - latitude: Double, - longitude: Double, - uncertainty: Double?, - isUserLocation: Boolean): Event { + fun createLocationEvent( + roomId: String, + latitude: Double, + longitude: Double, + uncertainty: Double?, + isUserLocation: Boolean + ): Event { val geoUri = buildGeoUri(latitude, longitude, uncertainty) val assetType = if (isUserLocation) LocationAssetType.SELF else LocationAssetType.PIN val content = MessageLocationContent( @@ -250,11 +264,13 @@ internal class LocalEchoEventFactory @Inject constructor( return createMessageEvent(roomId, content) } - fun createLiveLocationEvent(beaconInfoEventId: String, - roomId: String, - latitude: Double, - longitude: Double, - uncertainty: Double?): Event { + fun createLiveLocationEvent( + beaconInfoEventId: String, + roomId: String, + latitude: Double, + longitude: Double, + uncertainty: Double? + ): Event { val geoUri = buildGeoUri(latitude, longitude, uncertainty) val content = MessageBeaconLocationDataContent( body = geoUri, @@ -277,13 +293,15 @@ internal class LocalEchoEventFactory @Inject constructor( ) } - fun createReplaceTextOfReply(roomId: String, - eventReplaced: TimelineEvent, - originalEvent: TimelineEvent, - newBodyText: String, - autoMarkdown: Boolean, - msgType: String, - compatibilityText: String): Event { + fun createReplaceTextOfReply( + roomId: String, + eventReplaced: TimelineEvent, + originalEvent: TimelineEvent, + newBodyText: String, + autoMarkdown: Boolean, + msgType: String, + compatibilityText: String + ): Event { val permalink = permalinkFactory.createPermalink(roomId, originalEvent.root.eventId ?: "", false) val userLink = originalEvent.root.senderId?.let { permalinkFactory.createPermalink(it, false) } ?: "" @@ -321,16 +339,17 @@ internal class LocalEchoEventFactory @Inject constructor( ) } - fun createMediaEvent(roomId: String, - attachment: ContentAttachmentData, - rootThreadEventId: String? + fun createMediaEvent( + roomId: String, + attachment: ContentAttachmentData, + rootThreadEventId: String? ): Event { return when (attachment.type) { - ContentAttachmentData.Type.IMAGE -> createImageEvent(roomId, attachment, rootThreadEventId) - ContentAttachmentData.Type.VIDEO -> createVideoEvent(roomId, attachment, rootThreadEventId) - ContentAttachmentData.Type.AUDIO -> createAudioEvent(roomId, attachment, isVoiceMessage = false, rootThreadEventId = rootThreadEventId) + ContentAttachmentData.Type.IMAGE -> createImageEvent(roomId, attachment, rootThreadEventId) + ContentAttachmentData.Type.VIDEO -> createVideoEvent(roomId, attachment, rootThreadEventId) + ContentAttachmentData.Type.AUDIO -> createAudioEvent(roomId, attachment, isVoiceMessage = false, rootThreadEventId = rootThreadEventId) ContentAttachmentData.Type.VOICE_MESSAGE -> createAudioEvent(roomId, attachment, isVoiceMessage = true, rootThreadEventId = rootThreadEventId) - ContentAttachmentData.Type.FILE -> createFileEvent(roomId, attachment, rootThreadEventId) + ContentAttachmentData.Type.FILE -> createFileEvent(roomId, attachment, rootThreadEventId) } } @@ -435,10 +454,11 @@ internal class LocalEchoEventFactory @Inject constructor( return createMessageEvent(roomId, content) } - private fun createAudioEvent(roomId: String, - attachment: ContentAttachmentData, - isVoiceMessage: Boolean, - rootThreadEventId: String? + private fun createAudioEvent( + roomId: String, + attachment: ContentAttachmentData, + isVoiceMessage: Boolean, + rootThreadEventId: String? ): Event { val content = MessageAudioContent( msgType = MessageType.MSGTYPE_AUDIO, @@ -534,7 +554,8 @@ internal class LocalEchoEventFactory @Inject constructor( text: CharSequence, msgType: String, autoMarkdown: Boolean, - formattedText: String?): Event { + formattedText: String? + ): Event { val content = formattedText?.let { TextContent(text.toString(), it) } ?: createTextContent(text, autoMarkdown) return createEvent( roomId, @@ -555,12 +576,14 @@ internal class LocalEchoEventFactory @Inject constructor( /** * Creates a reply to a regular timeline Event or a thread Event if needed. */ - fun createReplyTextEvent(roomId: String, - eventReplied: TimelineEvent, - replyText: CharSequence, - autoMarkdown: Boolean, - rootThreadEventId: String? = null, - showInThread: Boolean): Event? { + fun createReplyTextEvent( + roomId: String, + eventReplied: TimelineEvent, + replyText: CharSequence, + autoMarkdown: Boolean, + rootThreadEventId: String? = null, + showInThread: Boolean + ): Event? { // Fallbacks and event representation // TODO Add error/warning logs when any of this is null val permalink = permalinkFactory.createPermalink(eventReplied.root, false) ?: return null @@ -662,7 +685,7 @@ internal class LocalEchoEventFactory @Inject constructor( when (content?.msgType) { MessageType.MSGTYPE_EMOTE, MessageType.MSGTYPE_TEXT, - MessageType.MSGTYPE_NOTICE -> { + MessageType.MSGTYPE_NOTICE -> { var formattedText: String? = null if (content is MessageContentWithFormattedBody) { formattedText = content.matrixFormattedBody @@ -673,14 +696,14 @@ internal class LocalEchoEventFactory @Inject constructor( TextContent(content.body, formattedText) } } - MessageType.MSGTYPE_FILE -> return TextContent("sent a file.") - MessageType.MSGTYPE_AUDIO -> return TextContent("sent an audio file.") - MessageType.MSGTYPE_IMAGE -> return TextContent("sent an image.") - MessageType.MSGTYPE_VIDEO -> return TextContent("sent a video.") + MessageType.MSGTYPE_FILE -> return TextContent("sent a file.") + MessageType.MSGTYPE_AUDIO -> return TextContent("sent an audio file.") + MessageType.MSGTYPE_IMAGE -> return TextContent("sent an image.") + MessageType.MSGTYPE_VIDEO -> return TextContent("sent a video.") MessageType.MSGTYPE_POLL_START -> { return TextContent((content as? MessagePollContent)?.getBestPollCreationInfo()?.question?.getBestQuestion() ?: "") } - else -> return TextContent(content?.body ?: "") + else -> return TextContent(content?.body ?: "") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt index bed590fd09816e683f0ed37738ef205813b04f75..394cb8944f451ff4fb496efa54b8600d17d468e7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt @@ -201,7 +201,7 @@ internal class LocalEchoRepository @Inject constructor( // need to resend the attachment true } - else -> { + else -> { Timber.e("Cannot resend message ${event.root.getClearType()} / ${content.msgType}") false } @@ -211,7 +211,7 @@ internal class LocalEchoRepository @Inject constructor( false } } - else -> { + else -> { Timber.e("Unsupported message to resend ${event.root.getClearType()}") false } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt index 1c0da4839ab64b3be55b7309c9f504ad55ad6169..765c282b65f09e916bb56647f1ce45f6047a96e0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt @@ -71,7 +71,7 @@ internal class RedactEventWorker(context: Context, params: WorkerParameters, ses { when (it) { is Failure.NetworkConnection -> Result.retry() - else -> { + else -> { // TODO mark as failed to send? // always return success, or the chain will be stuck for ever! Result.success( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/TextContentExtension.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/TextContentExtension.kt index 49bc05f40c92f632b5bd6eff298542f576981b8c..c5728ba527682bbe827f5a440f318a675441ca77 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/TextContentExtension.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/TextContentExtension.kt @@ -43,7 +43,8 @@ internal fun TextContent.toMessageTextContent(msgType: String = MessageType.MSGT internal fun TextContent.toThreadTextContent( rootThreadEventId: String, latestThreadEventId: String, - msgType: String = MessageType.MSGTYPE_TEXT): MessageTextContent { + msgType: String = MessageType.MSGTYPE_TEXT +): MessageTextContent { return MessageTextContent( msgType = msgType, format = MessageFormat.FORMAT_MATRIX_HTML.takeIf { formattedText != null }, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/WaveFormSanitizer.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/WaveFormSanitizer.kt index 78a03f3775c6e7aa4f3ed5134ea26cef199b9986..c7ca2e770fedb0a3d503031a139cddb06816a411 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/WaveFormSanitizer.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/WaveFormSanitizer.kt @@ -58,7 +58,7 @@ internal class WaveFormSanitizer @Inject constructor() { } } } - else -> { + else -> { sizeInRangeList.addAll(waveForm) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/MentionLinkSpecComparator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/MentionLinkSpecComparator.kt index 3d235ec4d6427b0fe3e44add63d195e5e06bdce0..db5eec7e7e8cf774f3f20cb5df217f5a1a08cccf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/MentionLinkSpecComparator.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/MentionLinkSpecComparator.kt @@ -24,9 +24,9 @@ internal class MentionLinkSpecComparator @Inject constructor() : Comparator<Ment return when { o1.start < o2.start -> -1 o1.start > o2.start -> 1 - o1.end < o2.end -> 1 - o1.end > o2.end -> -1 - else -> 0 + o1.end < o2.end -> 1 + o1.end > o2.end -> -1 + else -> 0 } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt index fa2e0052abd8c197a934da65cb366074c438d2be..38bddae951d52f8a93e312060d93f9c52cf12922 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt @@ -90,7 +90,7 @@ internal class TextPillsUtils @Inject constructor( // test if there is an overlap if (b.start in a.start until a.end) { when { - b.end <= a.end -> + b.end <= a.end -> // b is inside a -> b should be removed remove = i + 1 a.end - a.start > b.end - b.start -> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt index 8ef631ad36a499f148fe0c23f0e8b8d5b4ef1ae0..2c7eea1e5436d4c3fc7db5cfaa744f87f0eddfe3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt @@ -150,13 +150,13 @@ internal class EventSenderProcessorCoroutine @Inject constructor( canReachServer.set(false) task.markAsFailedOrRetry(exception, 0) } - (exception.isLimitExceededError()) -> { + (exception.isLimitExceededError()) -> { task.markAsFailedOrRetry(exception, exception.getRetryDelay(3_000)) } - exception is CancellationException -> { + exception is CancellationException -> { Timber.v("## $task has been cancelled, try next task") } - else -> { + else -> { Timber.v("## un-retryable error for $task, try next task") // this task is in error, check next one? task.onTaskFailed() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt index 301f8cb9d67f811840fd98977e1a585894063d15..c5b13043d7c5f49399ba4d18c624b5cb8c589494 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt @@ -180,7 +180,7 @@ internal class EventSenderProcessorThread @Inject constructor( waitForNetwork() } } - (exception.isLimitExceededError()) -> { + (exception.isLimitExceededError()) -> { if (task.retryCount.getAndIncrement() >= 3) task.onTaskFailed() Timber.v("## SendThread retryLoop retryable error for $task reason: ${exception.localizedMessage}") // wait a bit @@ -188,17 +188,17 @@ internal class EventSenderProcessorThread @Inject constructor( sleep(3_000) continue@retryLoop } - exception.isTokenError() -> { + exception.isTokenError() -> { Timber.v("## SendThread retryLoop retryable TOKEN error, interrupt") // we can exit the loop task.onTaskFailed() throw InterruptedException() } - exception is CancellationException -> { + exception is CancellationException -> { Timber.v("## SendThread task has been cancelled") break@retryLoop } - else -> { + else -> { Timber.v("## SendThread retryLoop Un-Retryable error, try next task") // this task is in error, check next one? task.onTaskFailed() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueueMemento.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueueMemento.kt index 545fc4173729fa91381a99c4faac96a0b091e254..0eedd4bd4d42b12c314986ee04ff91cf596c8680 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueueMemento.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueueMemento.kt @@ -35,11 +35,13 @@ import javax.inject.Inject private const val PERSISTENCE_KEY = "ManagedBySender" -internal class QueueMemento @Inject constructor(context: Context, - @SessionId sessionId: String, - private val queuedTaskFactory: QueuedTaskFactory, - private val localEchoRepository: LocalEchoRepository, - private val cryptoService: CryptoService) { +internal class QueueMemento @Inject constructor( + context: Context, + @SessionId sessionId: String, + private val queuedTaskFactory: QueuedTaskFactory, + private val localEchoRepository: LocalEchoRepository, + private val cryptoService: CryptoService +) { private val storage = context.getSharedPreferences("QueueMemento_$sessionId", Context.MODE_PRIVATE) private val trackedTasks = mutableListOf<QueuedTask>() @@ -74,11 +76,11 @@ internal class QueueMemento @Inject constructor(context: Context, encrypt = task.encrypt, order = order ) - is RedactQueuedTask -> RedactEventTaskInfo( + is RedactQueuedTask -> RedactEventTaskInfo( redactionLocalEcho = task.redactionLocalEchoId, order = order ) - else -> null + else -> null } } @@ -92,7 +94,7 @@ internal class QueueMemento @Inject constructor(context: Context, ?.forEach { info -> try { when (info) { - is SendEventTaskInfo -> { + is SendEventTaskInfo -> { localEchoRepository.getUpToDateEcho(info.localEchoId)?.let { if (it.sendState.isSending() && it.eventId != null && it.roomId != null) { localEchoRepository.updateSendState(it.eventId, it.roomId, SendState.UNSENT) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueuedTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueuedTask.kt index 948786677d4803cb43a040b5c75f1ab77b7fdc1f..983701857f05fa5e246cd9bed26681e105b70640 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueuedTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueuedTask.kt @@ -21,8 +21,8 @@ import timber.log.Timber import java.util.concurrent.atomic.AtomicInteger /** - * @param queueIdentifier String value to identify a unique Queue - * @param taskIdentifier String value to identify a unique Task. Should be different from queueIdentifier + * @property queueIdentifier String value to identify a unique Queue + * @property taskIdentifier String value to identify a unique Task. Should be different from queueIdentifier */ internal abstract class QueuedTask( val queueIdentifier: String, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/SendEventQueuedTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/SendEventQueuedTask.kt index 49492e79907dd44fc1735b760b7ccd5f63772403..1ba4e09cafc0e3c3cd2b7a020c4490b4a76bd11b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/SendEventQueuedTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/SendEventQueuedTask.kt @@ -45,7 +45,7 @@ internal class SendEventQueuedTask( localEchoRepository.deleteFailedEchoAsync(eventId = event.eventId, roomId = event.roomId ?: "") // TODO update aggregation :/ or it will stay locally } - else -> { + else -> { localEchoRepository.updateSendState(event.eventId!!, event.roomId, SendState.UNDELIVERED) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt index 60231892e104ddf9ef784d0a5bfd18bba898aeae..2a980f32863e77ac2a4bf38d3d2330599a449942 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt @@ -41,11 +41,12 @@ import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.session.content.FileUploader import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder -internal class DefaultStateService @AssistedInject constructor(@Assisted private val roomId: String, - private val stateEventDataSource: StateEventDataSource, - private val sendStateTask: SendStateTask, - private val fileUploader: FileUploader, - private val viaParameterFinder: ViaParameterFinder +internal class DefaultStateService @AssistedInject constructor( + @Assisted private val roomId: String, + private val stateEventDataSource: StateEventDataSource, + private val sendStateTask: SendStateTask, + private val fileUploader: FileUploader, + private val viaParameterFinder: ViaParameterFinder ) : StateService { @AssistedFactory @@ -87,7 +88,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private // Safe treatment for PowerLevelContent return when (eventType) { EventType.STATE_ROOM_POWER_LEVELS -> toSafePowerLevelsContentDict() - else -> this + else -> this } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt index 42d6677409472eceb21143af01eabc79f5e8628d..18c709adf2d2b3f1ac470ec672bd525632715203 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/StateEventDataSource.kt @@ -76,10 +76,11 @@ internal class StateEventDataSource @Inject constructor( } } - private fun buildStateEventQuery(realm: Realm, - roomId: String, - eventTypes: Set<String>, - stateKey: QueryStringValue + private fun buildStateEventQuery( + realm: Realm, + roomId: String, + eventTypes: Set<String>, + stateKey: QueryStringValue ): RealmQuery<CurrentStateEventEntity> { return with(queryStringValueProcessor) { realm.where<CurrentStateEventEntity>() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/GraphUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/GraphUtils.kt index 496bc7097fe1e6b910e50d47bf9d81778e4320a2..f10479d873aa1e6c2ebd360743c86fee8a40ce3a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/GraphUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/GraphUtils.kt @@ -101,11 +101,11 @@ internal class Graph { // it's a candidate destination = it.destination } - inPath -> { + inPath -> { // Cycle!! backwardEdges.add(it) } - completed -> { + completed -> { // dead end } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/HierarchyLiveDataHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/HierarchyLiveDataHelper.kt index 29db8431fd117c12703ef37c2801aee34c24630a..b141dfffa7044c047536ce76af0b426b151402f3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/HierarchyLiveDataHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/HierarchyLiveDataHelper.kt @@ -24,7 +24,8 @@ import org.matrix.android.sdk.api.util.Optional internal class HierarchyLiveDataHelper( val spaceId: String, val memberships: List<Membership>, - val roomSummaryDataSource: RoomSummaryDataSource) { + val roomSummaryDataSource: RoomSummaryDataSource +) { private val sources = HashMap<String, LiveData<Optional<RoomSummary>>>() private val mediatorLiveData = MediatorLiveData<List<String>>() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt index 96e8d3c73f451c8ea1fa2c412258df8710ff3a83..cb7dc270e8c47085e6501631d0a30a77738ccc56 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt @@ -26,8 +26,9 @@ import com.zhuinden.monarchy.Monarchy import io.realm.Realm import io.realm.RealmQuery import io.realm.kotlin.where -import org.matrix.android.sdk.api.query.ActiveSpaceFilter +import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.RoomCategoryFilter +import org.matrix.android.sdk.api.query.SpaceFilter import org.matrix.android.sdk.api.query.isNormalized import org.matrix.android.sdk.api.session.room.ResultBoundaries import org.matrix.android.sdk.api.session.room.RoomSortOrder @@ -84,16 +85,20 @@ internal class RoomSummaryDataSource @Inject constructor( } } - fun getRoomSummaries(queryParams: RoomSummaryQueryParams, - sortOrder: RoomSortOrder = RoomSortOrder.NONE): List<RoomSummary> { + fun getRoomSummaries( + queryParams: RoomSummaryQueryParams, + sortOrder: RoomSortOrder = RoomSortOrder.NONE + ): List<RoomSummary> { return monarchy.fetchAllMappedSync( { roomSummariesQuery(it, queryParams).process(sortOrder) }, { roomSummaryMapper.map(it) } ) } - fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams, - sortOrder: RoomSortOrder = RoomSortOrder.NONE): LiveData<List<RoomSummary>> { + fun getRoomSummariesLive( + queryParams: RoomSummaryQueryParams, + sortOrder: RoomSortOrder = RoomSortOrder.NONE + ): LiveData<List<RoomSummary>> { return monarchy.findAllMappedWithChanges( { roomSummariesQuery(it, queryParams).process(sortOrder) @@ -102,8 +107,10 @@ internal class RoomSummaryDataSource @Inject constructor( ) } - fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams, - sortOrder: RoomSortOrder = RoomSortOrder.NONE): LiveData<List<RoomSummary>> { + fun getSpaceSummariesLive( + queryParams: SpaceSummaryQueryParams, + sortOrder: RoomSortOrder = RoomSortOrder.NONE + ): LiveData<List<RoomSummary>> { return getRoomSummariesLive(queryParams, sortOrder) } @@ -128,8 +135,10 @@ internal class RoomSummaryDataSource @Inject constructor( } } - fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams, - sortOrder: RoomSortOrder = RoomSortOrder.NONE): List<RoomSummary> { + fun getSpaceSummaries( + spaceSummaryQueryParams: SpaceSummaryQueryParams, + sortOrder: RoomSortOrder = RoomSortOrder.NONE + ): List<RoomSummary> { return getRoomSummaries(spaceSummaryQueryParams, sortOrder) } @@ -170,9 +179,11 @@ internal class RoomSummaryDataSource @Inject constructor( .sort(RoomSummaryEntityFields.BREADCRUMBS_INDEX) } - fun getSortedPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, - pagedListConfig: PagedList.Config, - sortOrder: RoomSortOrder): LiveData<PagedList<RoomSummary>> { + fun getSortedPagedRoomSummariesLive( + queryParams: RoomSummaryQueryParams, + pagedListConfig: PagedList.Config, + sortOrder: RoomSortOrder + ): LiveData<PagedList<RoomSummary>> { val realmDataSourceFactory = monarchy.createDataSourceFactory { realm -> roomSummariesQuery(realm, queryParams).process(sortOrder) } @@ -185,15 +196,18 @@ internal class RoomSummaryDataSource @Inject constructor( ) } - fun getUpdatablePagedRoomSummariesLive(queryParams: RoomSummaryQueryParams, - pagedListConfig: PagedList.Config, - sortOrder: RoomSortOrder): UpdatableLivePageResult { + fun getUpdatablePagedRoomSummariesLive( + queryParams: RoomSummaryQueryParams, + pagedListConfig: PagedList.Config, + sortOrder: RoomSortOrder, + getFlattenedParents: Boolean = false + ): UpdatableLivePageResult { val realmDataSourceFactory = monarchy.createDataSourceFactory { realm -> roomSummariesQuery(realm, queryParams).process(sortOrder) } val dataSourceFactory = realmDataSourceFactory.map { roomSummaryMapper.map(it) - } + }.map { if (getFlattenedParents) it.getWithParents() else it } val boundaries = MutableLiveData(ResultBoundaries()) @@ -232,6 +246,13 @@ internal class RoomSummaryDataSource @Inject constructor( } } + private fun RoomSummary.getWithParents(): RoomSummary { + val parents = flattenParentIds.mapNotNull { parentId -> + getRoomSummary(parentId) + } + return copy(flattenParents = parents) + } + fun getCountLive(queryParams: RoomSummaryQueryParams): LiveData<Int> { val liveRooms = monarchy.findAllManagedWithChanges { roomSummariesQuery(it, queryParams) @@ -258,29 +279,13 @@ internal class RoomSummaryDataSource @Inject constructor( private fun roomSummariesQuery(realm: Realm, queryParams: RoomSummaryQueryParams): RealmQuery<RoomSummaryEntity> { val query = with(queryStringValueProcessor) { RoomSummaryEntity.where(realm) - .process(RoomSummaryEntityFields.ROOM_ID, queryParams.roomId) - .let { - if (queryParams.displayName.isNormalized()) { - it.process(RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME, queryParams.displayName) - } else { - it.process(RoomSummaryEntityFields.DISPLAY_NAME, queryParams.displayName) - } - } + .process(RoomSummaryEntityFields.ROOM_ID, QueryStringValue.IsNotEmpty) + .process(queryParams.displayName.toDisplayNameField(), queryParams.displayName) .process(RoomSummaryEntityFields.CANONICAL_ALIAS, queryParams.canonicalAlias) .process(RoomSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships) .equalTo(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, false) } - queryParams.roomCategoryFilter?.let { - when (it) { - RoomCategoryFilter.ONLY_DM -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true) - RoomCategoryFilter.ONLY_ROOMS -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false) - RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS -> query.greaterThan(RoomSummaryEntityFields.NOTIFICATION_COUNT, 0) - RoomCategoryFilter.ALL -> { - // nop - } - } - } queryParams.roomTagQueryFilter?.let { it.isFavorite?.let { fav -> query.equalTo(RoomSummaryEntityFields.IS_FAVOURITE, fav) @@ -300,31 +305,27 @@ internal class RoomSummaryDataSource @Inject constructor( query.equalTo(RoomSummaryEntityFields.ROOM_TYPE, it) } when (queryParams.roomCategoryFilter) { - RoomCategoryFilter.ONLY_DM -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true) - RoomCategoryFilter.ONLY_ROOMS -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false) + RoomCategoryFilter.ONLY_DM -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true) + RoomCategoryFilter.ONLY_ROOMS -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false) RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS -> query.greaterThan(RoomSummaryEntityFields.NOTIFICATION_COUNT, 0) - RoomCategoryFilter.ALL -> Unit // nop - null -> Unit + null -> Unit } // Timber.w("VAL: activeSpaceId : ${queryParams.activeSpaceId}") - when (queryParams.activeSpaceFilter) { - is ActiveSpaceFilter.ActiveSpace -> { + when (queryParams.spaceFilter) { + SpaceFilter.OrphanRooms -> { + // orphan rooms + query.isNull(RoomSummaryEntityFields.FLATTEN_PARENT_IDS) + } + is SpaceFilter.ActiveSpace -> { // It's annoying but for now realm java does not support querying in primitive list :/ // https://github.com/realm/realm-java/issues/5361 - if (queryParams.activeSpaceFilter.currentSpaceId == null) { - // orphan rooms - query.isNull(RoomSummaryEntityFields.FLATTEN_PARENT_IDS) - } else { - query.contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, queryParams.activeSpaceFilter.currentSpaceId) - } - } - is ActiveSpaceFilter.ExcludeSpace -> { - query.not().contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, queryParams.activeSpaceFilter.spaceId) + query.contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, queryParams.spaceFilter.spaceId) } - else -> { - // nop + is SpaceFilter.ExcludeSpace -> { + query.not().contains(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, queryParams.spaceFilter.spaceId) } + null -> Unit // nop } queryParams.activeGroupId?.let { activeGroupId -> @@ -333,6 +334,14 @@ internal class RoomSummaryDataSource @Inject constructor( return query } + private fun QueryStringValue.toDisplayNameField(): String { + return if (isNormalized()) { + RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME + } else { + RoomSummaryEntityFields.DISPLAY_NAME + } + } + fun getAllRoomSummaryChildOf(spaceAliasOrId: String, memberShips: List<Membership>): List<RoomSummary> { val space = getSpaceSummary(spaceAliasOrId) ?: return emptyList() val result = ArrayList<RoomSummary>() @@ -427,11 +436,13 @@ internal class RoomSummaryDataSource @Inject constructor( } } - fun flattenSubSpace(current: RoomSummary, - parenting: List<String>, - output: MutableList<RoomSummary>, - memberShips: List<Membership>, - includeCurrent: Boolean = true) { + fun flattenSubSpace( + current: RoomSummary, + parenting: List<String>, + output: MutableList<RoomSummary>, + memberShips: List<Membership>, + includeCurrent: Boolean = true + ) { if (includeCurrent) { output.add(current) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt index 611d6dc65e7a84b70885ab60eb21d92962fb613e..e4afe7aa49dadee1905ead0a64c499e3a1dcd33f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt @@ -85,13 +85,15 @@ internal class RoomSummaryUpdater @Inject constructor( } } - fun update(realm: Realm, - roomId: String, - membership: Membership? = null, - roomSummary: RoomSyncSummary? = null, - unreadNotifications: RoomSyncUnreadNotifications? = null, - updateMembers: Boolean = false, - inviterId: String? = null) { + fun update( + realm: Realm, + roomId: String, + membership: Membership? = null, + roomSummary: RoomSyncSummary? = null, + unreadNotifications: RoomSyncUnreadNotifications? = null, + updateMembers: Boolean = false, + inviterId: String? = null + ) { val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId) if (roomSummary != null) { if (roomSummary.heroes.isNotEmpty()) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt index fad21c09180f9a3e8d9c9061f5201368408453e9..7795a56cbf44ce60b6a66962f05d0892dcf1b1bb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.room.timeline import io.realm.Realm import io.realm.RealmConfiguration +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.android.asCoroutineDispatcher @@ -235,11 +236,15 @@ internal class DefaultTimeline( val loadMoreResult = try { strategy.loadMore(count, direction, fetchOnServerIfNeeded) } catch (throwable: Throwable) { - // Timeline could not be loaded with a (likely) permanent issue, such as the - // server now knowing the initialEventId, so we want to show an error message - // and possibly restart without initialEventId. - onTimelineFailure(throwable) - return false + if (throwable is CancellationException) { + LoadMoreResult.FAILURE + } else { + // Timeline could not be loaded with a (likely) permanent issue, such as the + // server now knowing the initialEventId, so we want to show an error message + // and possibly restart without initialEventId. + onTimelineFailure(throwable) + return false + } } Timber.v("$baseLogMessage: result $loadMoreResult") val hasMoreToLoad = loadMoreResult != LoadMoreResult.REACHED_END @@ -259,8 +264,8 @@ internal class DefaultTimeline( strategy = when { rootThreadEventId != null -> buildStrategy(LoadTimelineStrategy.Mode.Thread(rootThreadEventId)) - eventId == null -> buildStrategy(LoadTimelineStrategy.Mode.Live) - else -> buildStrategy(LoadTimelineStrategy.Mode.Permalink(eventId)) + eventId == null -> buildStrategy(LoadTimelineStrategy.Mode.Live) + else -> buildStrategy(LoadTimelineStrategy.Mode.Permalink(eventId)) } rootThreadEventId?.let { @@ -344,7 +349,7 @@ internal class DefaultTimeline( private fun updateState(direction: Timeline.Direction, update: (Timeline.PaginationState) -> Timeline.PaginationState) { val stateReference = when (direction) { - Timeline.Direction.FORWARDS -> forwardState + Timeline.Direction.FORWARDS -> forwardState Timeline.Direction.BACKWARDS -> backwardState } val currentValue = stateReference.get() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveTimelineEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveTimelineEvent.kt index e765e05578833c577c1fdcc9955318307ca04704..4be97efd6c80175082236769eb7b50f09e219aab 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveTimelineEvent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveTimelineEvent.kt @@ -36,11 +36,13 @@ import org.matrix.android.sdk.internal.database.query.where /** * This class takes care of handling case where local echo is replaced by the synced event in the db. */ -internal class LiveTimelineEvent(private val monarchy: Monarchy, - private val coroutineScope: CoroutineScope, - private val timelineEventMapper: TimelineEventMapper, - private val roomId: String, - private val eventId: String) : +internal class LiveTimelineEvent( + private val monarchy: Monarchy, + private val coroutineScope: CoroutineScope, + private val timelineEventMapper: TimelineEventMapper, + private val roomId: String, + private val eventId: String +) : MediatorLiveData<Optional<TimelineEvent>>() { init { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt index 4f65f85ce4ac31f4c03578068c5f1a3a013a5d9b..c5d4d346fdf8b82dbf7b4f490fd118468d305a41 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LoadTimelineStrategy.kt @@ -267,7 +267,7 @@ internal class LoadTimelineStrategy constructor( private fun getChunkEntity(realm: Realm): RealmResults<ChunkEntity> { return when (mode) { - is Mode.Live -> { + is Mode.Live -> { ChunkEntity.where(realm, roomId) .equalTo(ChunkEntityFields.IS_LAST_FORWARD, true) .findAll() @@ -275,7 +275,7 @@ internal class LoadTimelineStrategy constructor( is Mode.Permalink -> { ChunkEntity.findAllIncludingEvents(realm, listOf(mode.originEventId)) } - is Mode.Thread -> { + is Mode.Thread -> { recreateThreadChunkEntity(realm, mode.rootThreadEventId) ChunkEntity.where(realm, roomId) .equalTo(ChunkEntityFields.ROOT_THREAD_EVENT_ID, mode.rootThreadEventId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationDirection.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationDirection.kt index 930d01759e2e805a68fdb4b07685b0885bc687b6..37092de9c4155d3529f4578ef3ac084ae9f69e2f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationDirection.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/PaginationDirection.kt @@ -31,7 +31,7 @@ internal enum class PaginationDirection(val value: String) { fun reversed(): PaginationDirection { return when (this) { - FORWARDS -> BACKWARDS + FORWARDS -> BACKWARDS BACKWARDS -> FORWARDS } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineChunk.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineChunk.kt index 6a5f9da8a64400255e9873968c870ec393b0095d..e13f3f454fb0af42327164318f449a255053b38f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineChunk.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineChunk.kt @@ -70,6 +70,7 @@ internal class TimelineChunk( private val isLastForward = AtomicBoolean(chunkEntity.isLastForward) private val isLastBackward = AtomicBoolean(chunkEntity.isLastBackward) + private val nextToken = chunkEntity.nextToken private var prevChunkLatch: CompletableDeferred<Unit>? = null private var nextChunkLatch: CompletableDeferred<Unit>? = null @@ -136,8 +137,10 @@ internal class TimelineChunk( val prevEvents = prevChunk?.builtItems(includesNext = false, includesPrev = true).orEmpty() deepBuiltItems.addAll(prevEvents) } - - return deepBuiltItems + // In some scenario (permalink) we might end up with duplicate timeline events, so we want to be sure we only expose one. + return deepBuiltItems.distinctBy { + it.eventId + } } /** @@ -154,10 +157,6 @@ internal class TimelineChunk( val loadFromStorage = loadFromStorage(count, direction).also { logLoadedFromStorage(it, direction) } - if (loadFromStorage.numberOfEvents == 6) { - Timber.i("here") - } - val offsetCount = count - loadFromStorage.numberOfEvents return if (offsetCount == 0) { @@ -213,7 +212,7 @@ internal class TimelineChunk( fetchFromServerIfNeeded -> { fetchFromServer(offsetCount, chunkEntity.nextToken, direction) } - else -> { + else -> { LoadMoreResult.SUCCESS } } @@ -231,7 +230,7 @@ internal class TimelineChunk( fetchFromServerIfNeeded -> { fetchFromServer(offsetCount, chunkEntity.prevToken, direction) } - else -> { + else -> { LoadMoreResult.SUCCESS } } @@ -251,10 +250,6 @@ internal class TimelineChunk( } fun getBuiltEventIndex(eventId: String, searchInNext: Boolean, searchInPrev: Boolean): Int? { - val builtEventIndex = builtEventsIndexes[eventId] - if (builtEventIndex != null) { - return getOffsetIndex() + builtEventIndex - } if (searchInNext) { val nextBuiltEventIndex = nextChunk?.getBuiltEventIndex(eventId, searchInNext = true, searchInPrev = false) if (nextBuiltEventIndex != null) { @@ -267,7 +262,12 @@ internal class TimelineChunk( return prevBuiltEventIndex } } - return null + val builtEventIndex = builtEventsIndexes[eventId] + return if (builtEventIndex != null) { + getOffsetIndex() + builtEventIndex + } else { + null + } } fun getBuiltEvent(eventId: String, searchInNext: Boolean, searchInPrev: Boolean): TimelineEvent? { @@ -445,7 +445,7 @@ internal class TimelineChunk( Timber.e(failure, "Failed to fetch from server") LoadMoreResult.FAILURE } - return if (loadMoreResult == LoadMoreResult.SUCCESS) { + return if (loadMoreResult != LoadMoreResult.FAILURE) { latch?.await() loadMore(count, direction, fetchOnServerIfNeeded = false) } else { @@ -457,7 +457,7 @@ internal class TimelineChunk( return when (this) { TokenChunkEventPersistor.Result.REACHED_END -> LoadMoreResult.REACHED_END TokenChunkEventPersistor.Result.SHOULD_FETCH_MORE, - TokenChunkEventPersistor.Result.SUCCESS -> LoadMoreResult.SUCCESS + TokenChunkEventPersistor.Result.SUCCESS -> LoadMoreResult.SUCCESS } } @@ -465,16 +465,20 @@ internal class TimelineChunk( return when (this) { DefaultFetchThreadTimelineTask.Result.REACHED_END -> LoadMoreResult.REACHED_END DefaultFetchThreadTimelineTask.Result.SHOULD_FETCH_MORE, - DefaultFetchThreadTimelineTask.Result.SUCCESS -> LoadMoreResult.SUCCESS + DefaultFetchThreadTimelineTask.Result.SUCCESS -> LoadMoreResult.SUCCESS } } private fun getOffsetIndex(): Int { + if (nextToken == null) return 0 var offset = 0 var currentNextChunk = nextChunk while (currentNextChunk != null) { offset += currentNextChunk.builtEvents.size - currentNextChunk = currentNextChunk.nextChunk + currentNextChunk = currentNextChunk.nextChunk?.takeIf { + // In case of permalink we can end up with a linked nextChunk (which is the lastForward Chunk) but no nextToken + it.nextToken != null + } } return offset } @@ -486,6 +490,35 @@ internal class TimelineChunk( private fun handleDatabaseChangeSet(results: RealmResults<TimelineEventEntity>, changeSet: OrderedCollectionChangeSet) { val insertions = changeSet.insertionRanges for (range in insertions) { + // Check if the insertion's displayIndices match our expectations - or skip this insertion. + // Inconsistencies (missing messages) can happen otherwise if we get insertions before having loaded all timeline events of the chunk. + if (builtEvents.isNotEmpty()) { + // Check consistency to item before insertions + if (range.startIndex > 0) { + val firstInsertion = results[range.startIndex]!! + val lastBeforeInsertion = builtEvents[range.startIndex - 1] + if (firstInsertion.displayIndex + 1 != lastBeforeInsertion.displayIndex) { + Timber.i( + "handleDatabaseChangeSet: skip insertion at ${range.startIndex}/${builtEvents.size}, " + + "displayIndex mismatch at ${range.startIndex}: ${firstInsertion.displayIndex} -> ${lastBeforeInsertion.displayIndex}" + ) + continue + } + } + // Check consistency to item after insertions + if (range.startIndex < builtEvents.size) { + val lastInsertion = results[range.startIndex + range.length - 1]!! + val firstAfterInsertion = builtEvents[range.startIndex] + if (firstAfterInsertion.displayIndex + 1 != lastInsertion.displayIndex) { + Timber.i( + "handleDatabaseChangeSet: skip insertion at ${range.startIndex}/${builtEvents.size}, " + + "displayIndex mismatch at ${range.startIndex + range.length}: " + + "${firstAfterInsertion.displayIndex} -> ${lastInsertion.displayIndex}" + ) + continue + } + } + } val newItems = results .subList(range.startIndex, range.startIndex + range.length) .map { it.buildAndDecryptIfNeeded() } @@ -503,8 +536,12 @@ internal class TimelineChunk( for (range in modifications) { for (modificationIndex in (range.startIndex until range.startIndex + range.length)) { val updatedEntity = results[modificationIndex] ?: continue + val displayIndex = builtEventsIndexes[updatedEntity.eventId] + if (displayIndex == null) { + continue + } try { - builtEvents[modificationIndex] = updatedEntity.buildAndDecryptIfNeeded() + builtEvents[displayIndex] = updatedEntity.buildAndDecryptIfNeeded() } catch (failure: Throwable) { Timber.v("Fail to update items at index: $modificationIndex") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt index 8b58d3ca5c111064da10d2b813a68e80724b2a24..b1b9e4bb2280f5bca2451c9ed756eb286d99ea8d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDataSource.kt @@ -33,10 +33,12 @@ import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.task.TaskExecutor import javax.inject.Inject -internal class TimelineEventDataSource @Inject constructor(private val realmSessionProvider: RealmSessionProvider, - private val timelineEventMapper: TimelineEventMapper, - private val taskExecutor: TaskExecutor, - @SessionDatabase private val monarchy: Monarchy) { +internal class TimelineEventDataSource @Inject constructor( + private val realmSessionProvider: RealmSessionProvider, + private val timelineEventMapper: TimelineEventMapper, + private val taskExecutor: TaskExecutor, + @SessionDatabase private val monarchy: Monarchy +) { fun getTimelineEvent(roomId: String, eventId: String): TimelineEvent? { return realmSessionProvider.withRealm { realm -> @@ -54,7 +56,8 @@ internal class TimelineEventDataSource @Inject constructor(private val realmSess // TODO pretty bad query.. maybe we should denormalize clear type in base? return realmSessionProvider.withRealm { realm -> TimelineEventEntity.whereRoomId(realm, roomId) - .sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING) + .sort(TimelineEventEntityFields.ROOT.ORIGIN_SERVER_TS, Sort.ASCENDING) + .distinct(TimelineEventEntityFields.EVENT_ID) .findAll() ?.mapNotNull { timelineEventMapper.map(it).takeIf { it.root.isImageMessage() || it.root.isVideoMessage() } } .orEmpty() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEvent.kt index 465b0faac8058f2c72b023192cdb07c69e1ece37..e9626a2173b62aded80135a5703238d0fee38dda 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEvent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEvent.kt @@ -24,5 +24,5 @@ internal interface TokenChunkEvent { val events: List<Event> val stateEvents: List<Event>? - fun hasMore() = start != end + fun hasMore() = end != null && start != end } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt index 96ceb6c6dca21ead391b0a860d527f79daee07df..fd1703dbc8a507a0886f5d5bfff211b91541e895 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt @@ -33,12 +33,10 @@ import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.EventEntity import org.matrix.android.sdk.internal.database.model.EventInsertType import org.matrix.android.sdk.internal.database.model.RoomEntity -import org.matrix.android.sdk.internal.database.model.TimelineEventEntity -import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore import org.matrix.android.sdk.internal.database.query.create import org.matrix.android.sdk.internal.database.query.find -import org.matrix.android.sdk.internal.database.query.findAll +import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.UserId @@ -65,9 +63,11 @@ internal class TokenChunkEventPersistor @Inject constructor( SUCCESS } - suspend fun insertInDb(receivedChunk: TokenChunkEvent, - roomId: String, - direction: PaginationDirection): Result { + suspend fun insertInDb( + receivedChunk: TokenChunkEvent, + roomId: String, + direction: PaginationDirection + ): Result { monarchy .awaitTransaction { realm -> Timber.v("Start persisting ${receivedChunk.events.size} events in $roomId towards $direction") @@ -81,27 +81,22 @@ internal class TokenChunkEventPersistor @Inject constructor( nextToken = receivedChunk.start prevToken = receivedChunk.end } - val existingChunk = ChunkEntity.find(realm, roomId, prevToken = prevToken, nextToken = nextToken) if (existingChunk != null) { - Timber.v("This chunk is already in the db, checking if this might be caused by broken links") - existingChunk.fixChunkLinks(realm, roomId, direction, prevToken, nextToken) + Timber.v("This chunk is already in the db, return.") return@awaitTransaction } + + // Creates links in both directions val prevChunk = ChunkEntity.find(realm, roomId, nextToken = prevToken) val nextChunk = ChunkEntity.find(realm, roomId, prevToken = nextToken) val currentChunk = ChunkEntity.create(realm, prevToken = prevToken, nextToken = nextToken).apply { this.nextChunk = nextChunk this.prevChunk = prevChunk } - val allNextChunks = ChunkEntity.findAll(realm, roomId, prevToken = nextToken) - val allPrevChunks = ChunkEntity.findAll(realm, roomId, nextToken = prevToken) - allNextChunks?.forEach { - it.prevChunk = currentChunk - } - allPrevChunks?.forEach { - it.nextChunk = currentChunk - } + nextChunk?.prevChunk = currentChunk + prevChunk?.nextChunk = currentChunk + if (receivedChunk.events.isEmpty() && !receivedChunk.hasMore()) { handleReachEnd(roomId, direction, currentChunk) } else { @@ -120,38 +115,13 @@ internal class TokenChunkEventPersistor @Inject constructor( } } - private fun ChunkEntity.fixChunkLinks( - realm: Realm, - roomId: String, - direction: PaginationDirection, - prevToken: String?, - nextToken: String?, - ) { - if (direction == PaginationDirection.FORWARDS) { - val prevChunks = ChunkEntity.findAll(realm, roomId, nextToken = prevToken) - Timber.v("Found ${prevChunks?.size} prevChunks") - prevChunks?.forEach { - if (it.nextChunk != this) { - Timber.i("Set nextChunk for ${it.identifier()} from ${it.nextChunk?.identifier()} to ${identifier()}") - it.nextChunk = this - } - } - } else { - val nextChunks = ChunkEntity.findAll(realm, roomId, prevToken = nextToken) - Timber.v("Found ${nextChunks?.size} nextChunks") - nextChunks?.forEach { - if (it.prevChunk != this) { - Timber.i("Set prevChunk for ${it.identifier()} from ${it.prevChunk?.identifier()} to ${identifier()}") - it.prevChunk = this - } - } - } - } - private fun handleReachEnd(roomId: String, direction: PaginationDirection, currentChunk: ChunkEntity) { - Timber.v("Reach end of $roomId") + Timber.v("Reach end of $roomId in $direction") if (direction == PaginationDirection.FORWARDS) { - Timber.v("We should keep the lastForward chunk unique, the one from sync") + // We should keep the lastForward chunk unique, the one from sync, so make an unidirectional link. + // This will allow us to get live events from sync even from a permalink but won't make the link in the opposite. + val realm = currentChunk.realm + currentChunk.nextChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId) } else { currentChunk.isLastBackward = true } @@ -185,38 +155,8 @@ internal class TokenChunkEventPersistor @Inject constructor( if (event.eventId == null || event.senderId == null) { return@forEach } - // We check for the timeline event with this id, but not in the thread chunk - val eventId = event.eventId - val existingTimelineEvent = TimelineEventEntity - .where(realm, roomId, eventId) - .equalTo(TimelineEventEntityFields.OWNED_BY_THREAD_CHUNK, false) - .findFirst() - // If it exists, we want to stop here, just link the prevChunk - val existingChunk = existingTimelineEvent?.chunk?.firstOrNull() - if (existingChunk != null) { - when (direction) { - PaginationDirection.BACKWARDS -> { - if (currentChunk.nextChunk == existingChunk) { - Timber.w("Avoid double link, shouldn't happen in an ideal world") - } else { - currentChunk.prevChunk = existingChunk - existingChunk.nextChunk = currentChunk - } - } - PaginationDirection.FORWARDS -> { - if (currentChunk.prevChunk == existingChunk) { - Timber.w("Avoid double link, shouldn't happen in an ideal world") - } else { - currentChunk.nextChunk = existingChunk - existingChunk.prevChunk = currentChunk - } - } - } - // Stop processing here - return@processTimelineEvents - } val ageLocalTs = event.unsignedData?.age?.let { now - it } - var eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, EventInsertType.PAGINATION) + val eventEntity = event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, EventInsertType.PAGINATION) if (event.type == EventType.STATE_ROOM_MEMBER && event.stateKey != null) { val contentToUse = if (direction == PaginationDirection.BACKWARDS) { event.prevContent diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/UIEchoManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/UIEchoManager.kt index 66bb04400b320b61294fc3b3f982a5d7b8e2b56a..04c72b5d6d8340962acb22366ef2943083a5148a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/UIEchoManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/UIEchoManager.kt @@ -74,7 +74,7 @@ internal class UIEchoManager( when (timelineEvent.root.getClearType()) { EventType.REDACTION -> { } - EventType.REACTION -> { + EventType.REACTION -> { val content: ReactionContent? = timelineEvent.root.content?.toModel<ReactionContent>() if (RelationType.ANNOTATION == content?.relatesTo?.type) { val reaction = content.relatesTo.key diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt index 12ca36fa6bb52c31f9ed620cd20145490e050b9f..5e33631f2c904fa3ad392b30c19003c6f0799379 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/DefaultSearchService.kt @@ -24,14 +24,16 @@ internal class DefaultSearchService @Inject constructor( private val searchTask: SearchTask ) : SearchService { - override suspend fun search(searchTerm: String, - roomId: String, - nextBatch: String?, - orderByRecent: Boolean, - limit: Int, - beforeLimit: Int, - afterLimit: Int, - includeProfile: Boolean): SearchResult { + override suspend fun search( + searchTerm: String, + roomId: String, + nextBatch: String?, + orderByRecent: Boolean, + limit: Int, + beforeLimit: Int, + afterLimit: Int, + includeProfile: Boolean + ): SearchResult { return searchTask.execute( SearchTask.Params( searchTerm = searchTerm, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt index b5099e723874eb70aadbe87c254b6810cdac082b..4cd96c408aacfbb64e5ec8246aea118ce7230766 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/search/SearchAPI.kt @@ -30,6 +30,8 @@ internal interface SearchAPI { * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-search */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "search") - suspend fun search(@Query("next_batch") nextBatch: String?, - @Body body: SearchRequestBody): SearchResponse + suspend fun search( + @Query("next_batch") nextBatch: String?, + @Body body: SearchRequestBody + ): SearchResponse } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt index 07a5cbe5a0249d26f6f26b2c4b07d37dac73e57e..8b35bd173ee35dc73993e43bb610c39d7b3ac928 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt @@ -124,7 +124,7 @@ internal class SecretStoringUtils @Inject constructor( fun securelyStoreString(secret: String, keyAlias: String): ByteArray { return when { buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M -> encryptStringM(secret, keyAlias) - else -> encryptString(secret, keyAlias) + else -> encryptString(secret, keyAlias) } } @@ -138,8 +138,8 @@ internal class SecretStoringUtils @Inject constructor( // First get the format return when (val format = inputStream.read().toByte()) { FORMAT_API_M -> decryptStringM(inputStream, keyAlias) - FORMAT_1 -> decryptString(inputStream, keyAlias) - else -> throw IllegalArgumentException("Unknown format $format") + FORMAT_1 -> decryptString(inputStream, keyAlias) + else -> throw IllegalArgumentException("Unknown format $format") } } } @@ -148,7 +148,7 @@ internal class SecretStoringUtils @Inject constructor( fun securelyStoreObject(any: Any, keyAlias: String, output: OutputStream) { when { buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M -> saveSecureObjectM(keyAlias, output, any) - else -> saveSecureObject(keyAlias, output, any) + else -> saveSecureObject(keyAlias, output, any) } } @@ -157,8 +157,8 @@ internal class SecretStoringUtils @Inject constructor( // First get the format return when (val format = inputStream.read().toByte()) { FORMAT_API_M -> loadSecureObjectM(keyAlias, inputStream) - FORMAT_1 -> loadSecureObject(keyAlias, inputStream) - else -> throw IllegalArgumentException("Unknown format $format") + FORMAT_1 -> loadSecureObject(keyAlias, inputStream) + else -> throw IllegalArgumentException("Unknown format $format") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt index e7b20f905bb9b6e5efa3a54ee6f5c6724eb2425d..1bb86ecb4b4bc6d0b75aea02d4f595c29dfac361 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt @@ -21,9 +21,10 @@ import org.matrix.android.sdk.api.session.signout.SignOutService import org.matrix.android.sdk.internal.auth.SessionParamsStore import javax.inject.Inject -internal class DefaultSignOutService @Inject constructor(private val signOutTask: SignOutTask, - private val signInAgainTask: SignInAgainTask, - private val sessionParamsStore: SessionParamsStore +internal class DefaultSignOutService @Inject constructor( + private val signOutTask: SignOutTask, + private val signInAgainTask: SignInAgainTask, + private val sessionParamsStore: SessionParamsStore ) : SignOutService { override suspend fun signInAgain(password: String) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt index 178a29a5a01c06ea7d31de8142ad173c18b53be4..32faffa670c431faeb2c9d38b37bcb85ef9b7aaf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpace.kt @@ -44,11 +44,13 @@ internal class DefaultSpace( return spaceSummaryDataSource.getSpaceSummary(room.roomId) } - override suspend fun addChildren(roomId: String, - viaServers: List<String>?, - order: String?, + override suspend fun addChildren( + roomId: String, + viaServers: List<String>?, + order: String?, // autoJoin: Boolean, - suggested: Boolean?) { + suggested: Boolean? + ) { // Find best via val bestVia = viaServers ?: (spaceSummaryDataSource.getRoomSummary(roomId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt index 9320665688af7281e01c0182aa683be5e3516b35..c08d9389a87b5f5841b93eea8cd475b85f0d2bf9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt @@ -99,13 +99,17 @@ internal class DefaultSpaceService @Inject constructor( return spaceGetter.get(spaceId) } - override fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams, - sortOrder: RoomSortOrder): LiveData<List<RoomSummary>> { + override fun getSpaceSummariesLive( + queryParams: SpaceSummaryQueryParams, + sortOrder: RoomSortOrder + ): LiveData<List<RoomSummary>> { return roomSummaryDataSource.getSpaceSummariesLive(queryParams, sortOrder) } - override fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams, - sortOrder: RoomSortOrder): List<RoomSummary> { + override fun getSpaceSummaries( + spaceSummaryQueryParams: SpaceSummaryQueryParams, + sortOrder: RoomSortOrder + ): List<RoomSummary> { return roomSummaryDataSource.getSpaceSummaries(spaceSummaryQueryParams, sortOrder) } @@ -221,9 +225,11 @@ internal class DefaultSpaceService @Inject constructor( worldReadable = summary.isWorldReadable ) - override suspend fun joinSpace(spaceIdOrAlias: String, - reason: String?, - viaServers: List<String>): JoinSpaceResult { + override suspend fun joinSpace( + spaceIdOrAlias: String, + reason: String?, + viaServers: List<String> + ): JoinSpaceResult { return joinSpaceTask.execute(JoinSpaceTask.Params(spaceIdOrAlias, reason, viaServers)) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/SpaceApi.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/SpaceApi.kt index d8daa55e150e2bcd64e8be5548de35a0396cabd6..126245d01559a0ecee92f9475878dff5e6ae6399 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/SpaceApi.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/SpaceApi.kt @@ -24,11 +24,12 @@ import retrofit2.http.Query internal interface SpaceApi { /** + * @param spaceId the space Id * @param suggestedOnly Optional. If true, return only child events and rooms where the m.space.child event has suggested: true. - * @param limit: Optional: a client-defined limit to the maximum number of rooms to return per page. Must be a non-negative integer. - * @param maxDepth: Optional: The maximum depth in the tree (from the root room) to return. + * @param limit Optional: a client-defined limit to the maximum number of rooms to return per page. Must be a non-negative integer. + * @param maxDepth Optional: The maximum depth in the tree (from the root room) to return. * The deepest depth returned will not include children events. Defaults to no-limit. Must be a non-negative integer. - * @param from: Optional. Pagination token given to retrieve the next set of rooms. + * @param from Optional. Pagination token given to retrieve the next set of rooms. * Note that if a pagination token is provided, then the parameters given for suggested_only and max_depth must be the same. */ @GET(NetworkConstants.URI_API_PREFIX_PATH_V1 + "rooms/{roomId}/hierarchy") @@ -37,7 +38,8 @@ internal interface SpaceApi { @Query("suggested_only") suggestedOnly: Boolean?, @Query("limit") limit: Int?, @Query("max_depth") maxDepth: Int?, - @Query("from") from: String?): SpacesResponse + @Query("from") from: String? + ): SpacesResponse /** * Unstable version of [getSpaceHierarchy]. @@ -48,5 +50,6 @@ internal interface SpaceApi { @Query("suggested_only") suggestedOnly: Boolean?, @Query("limit") limit: Int?, @Query("max_depth") maxDepth: Int?, - @Query("from") from: String?): SpacesResponse + @Query("from") from: String? + ): SpacesResponse } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/DefaultSyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/DefaultSyncService.kt new file mode 100644 index 0000000000000000000000000000000000000000..37869b88f9d2688a0a53aba849998bf60aad173d --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/DefaultSyncService.kt @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.sync + +import androidx.lifecycle.LiveData +import org.matrix.android.sdk.api.session.sync.SyncRequestState +import org.matrix.android.sdk.api.session.sync.SyncService +import org.matrix.android.sdk.internal.di.SessionId +import org.matrix.android.sdk.internal.di.WorkManagerProvider +import org.matrix.android.sdk.internal.session.SessionState +import org.matrix.android.sdk.internal.session.sync.job.SyncThread +import org.matrix.android.sdk.internal.session.sync.job.SyncWorker +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Provider + +internal class DefaultSyncService @Inject constructor( + @SessionId val sessionId: String, + private val workManagerProvider: WorkManagerProvider, + private val syncThreadProvider: Provider<SyncThread>, + private val syncTokenStore: SyncTokenStore, + private val syncRequestStateTracker: SyncRequestStateTracker, + private val sessionState: SessionState, +) : SyncService { + private var syncThread: SyncThread? = null + + override fun requireBackgroundSync() { + SyncWorker.requireBackgroundSync(workManagerProvider, sessionId) + } + + override fun startAutomaticBackgroundSync(timeOutInSeconds: Long, repeatDelayInSeconds: Long) { + SyncWorker.automaticallyBackgroundSync(workManagerProvider, sessionId, timeOutInSeconds, repeatDelayInSeconds) + } + + override fun stopAnyBackgroundSync() { + SyncWorker.stopAnyBackgroundSync(workManagerProvider) + } + + override fun startSync(fromForeground: Boolean) { + Timber.i("Starting sync thread") + assert(sessionState.isOpen) + val localSyncThread = getSyncThread() + localSyncThread.setInitialForeground(fromForeground) + if (!localSyncThread.isAlive) { + localSyncThread.start() + } else { + localSyncThread.restart() + Timber.w("Attempt to start an already started thread") + } + } + + override fun stopSync() { + assert(sessionState.isOpen) + syncThread?.kill() + syncThread = null + } + + override fun getSyncStateLive() = getSyncThread().liveState() + + override fun syncFlow() = getSyncThread().syncFlow() + + override fun getSyncState() = getSyncThread().currentState() + + override fun getSyncRequestStateLive(): LiveData<SyncRequestState> { + return syncRequestStateTracker.syncRequestState + } + + override fun hasAlreadySynced(): Boolean { + return syncTokenStore.getLastToken() != null + } + + private fun getSyncThread(): SyncThread { + return syncThread ?: syncThreadProvider.get().also { + syncThread = it + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/Extensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..ae542103b787679f8780a7b2b5bfc331ded21c64 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/Extensions.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.sync + +import org.matrix.android.sdk.api.session.sync.InitialSyncStep + +internal inline fun <T> reportSubtask( + reporter: ProgressReporter?, + initialSyncStep: InitialSyncStep, + totalProgress: Int, + parentWeight: Float, + block: () -> T +): T { + reporter?.startTask(initialSyncStep, totalProgress, parentWeight) + return block().also { + reporter?.endTask() + } +} + +internal inline fun <K, V, R> Map<out K, V>.mapWithProgress( + reporter: ProgressReporter?, + initialSyncStep: InitialSyncStep, + parentWeight: Float, + transform: (Map.Entry<K, V>) -> R +): List<R> { + var current = 0F + reporter?.startTask(initialSyncStep, count() + 1, parentWeight) + return map { + reporter?.reportProgress(current) + current++ + transform.invoke(it) + }.also { + reporter?.endTask() + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/ProgressReporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/ProgressReporter.kt similarity index 74% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/ProgressReporter.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/ProgressReporter.kt index 8a7b26b4b8fbe6d9791e044a44af83fa2e4352f7..6d77b9be5e3b1f80e3cf17405f42d82bc7bf1c17 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/ProgressReporter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/ProgressReporter.kt @@ -14,14 +14,16 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.initsync +package org.matrix.android.sdk.internal.session.sync -import org.matrix.android.sdk.api.session.initsync.InitSyncStep +import org.matrix.android.sdk.api.session.sync.InitialSyncStep internal interface ProgressReporter { - fun startTask(initSyncStep: InitSyncStep, - totalProgress: Int, - parentWeight: Float) + fun startTask( + initialSyncStep: InitialSyncStep, + totalProgress: Int, + parentWeight: Float + ) fun reportProgress(progress: Float) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncAPI.kt index 6c8a71f35ecd02a6875d2d70fc0e9f5561eb88e6..2a2fd6ab1d889a8f7a60aece53c667b820bcf158 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncAPI.kt @@ -31,10 +31,11 @@ internal interface SyncAPI { * Set all the timeouts to 1 minute by default. */ @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "sync") - suspend fun sync(@QueryMap params: Map<String, String>, - @Header(TimeOutInterceptor.CONNECT_TIMEOUT) connectTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT, - @Header(TimeOutInterceptor.READ_TIMEOUT) readTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT, - @Header(TimeOutInterceptor.WRITE_TIMEOUT) writeTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT + suspend fun sync( + @QueryMap params: Map<String, String>, + @Header(TimeOutInterceptor.CONNECT_TIMEOUT) connectTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT, + @Header(TimeOutInterceptor.READ_TIMEOUT) readTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT, + @Header(TimeOutInterceptor.WRITE_TIMEOUT) writeTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT ): SyncResponse /** @@ -42,9 +43,10 @@ internal interface SyncAPI { */ @Streaming @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "sync") - fun syncStream(@QueryMap params: Map<String, String>, - @Header(TimeOutInterceptor.CONNECT_TIMEOUT) connectTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT, - @Header(TimeOutInterceptor.READ_TIMEOUT) readTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT, - @Header(TimeOutInterceptor.WRITE_TIMEOUT) writeTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT + fun syncStream( + @QueryMap params: Map<String, String>, + @Header(TimeOutInterceptor.CONNECT_TIMEOUT) connectTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT, + @Header(TimeOutInterceptor.READ_TIMEOUT) readTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT, + @Header(TimeOutInterceptor.WRITE_TIMEOUT) writeTimeOut: Long = TimeOutInterceptor.DEFAULT_LONG_TIMEOUT ): Call<ResponseBody> } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncModule.kt index 4b31dc4d9b00b7d9b488c0abc50604ca1c98364f..d78070439c51503c86d0cfa5d971d7c36df642e2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncModule.kt @@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.sync import dagger.Binds import dagger.Module import dagger.Provides +import org.matrix.android.sdk.api.session.sync.SyncService import org.matrix.android.sdk.internal.session.SessionScope import retrofit2.Retrofit @@ -35,6 +36,9 @@ internal abstract class SyncModule { } } + @Binds + abstract fun bindSyncService(service: DefaultSyncService): SyncService + @Binds abstract fun bindSyncTask(task: DefaultSyncTask): SyncTask diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncPresence.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncPresence.kt index ce41a4568cdf190c16a47da9739366a8c61a444b..9df6d52ad3b27b9c8fa8f1cc9b2a30daa1ae7244 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncPresence.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncPresence.kt @@ -35,9 +35,9 @@ internal enum class SyncPresence(val value: String) { companion object { fun from(presenceEnum: PresenceEnum): SyncPresence { return when (presenceEnum) { - PresenceEnum.ONLINE -> Online - PresenceEnum.OFFLINE -> Offline - PresenceEnum.BUSY -> Busy + PresenceEnum.ONLINE -> Online + PresenceEnum.OFFLINE -> Offline + PresenceEnum.BUSY -> Busy PresenceEnum.UNAVAILABLE -> Unavailable } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/DefaultSyncStatusService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncRequestStateTracker.kt similarity index 63% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/DefaultSyncStatusService.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncRequestStateTracker.kt index 2aa0be80c9b4e36473adc2d433e517532b5a09c5..bcc5fcf9abe0d059e76f993e7a24352301ba3e30 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/DefaultSyncStatusService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncRequestStateTracker.kt @@ -13,52 +13,51 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.matrix.android.sdk.internal.session.initsync -import androidx.lifecycle.LiveData +package org.matrix.android.sdk.internal.session.sync + import androidx.lifecycle.MutableLiveData -import org.matrix.android.sdk.api.session.initsync.InitSyncStep -import org.matrix.android.sdk.api.session.initsync.SyncStatusService +import org.matrix.android.sdk.api.session.sync.InitialSyncStep +import org.matrix.android.sdk.api.session.sync.SyncRequestState import org.matrix.android.sdk.internal.session.SessionScope import javax.inject.Inject @SessionScope -internal class DefaultSyncStatusService @Inject constructor() : - SyncStatusService, +internal class SyncRequestStateTracker @Inject constructor() : ProgressReporter { - private val status = MutableLiveData<SyncStatusService.Status>() + val syncRequestState = MutableLiveData<SyncRequestState>() private var rootTask: TaskInfo? = null - override fun getSyncStatusLive(): LiveData<SyncStatusService.Status> { - return status - } - // Only to be used for incremental sync - fun setStatus(newStatus: SyncStatusService.Status.IncrementalSyncStatus) { - status.postValue(newStatus) + fun setSyncRequestState(newSyncRequestState: SyncRequestState.IncrementalSyncRequestState) { + syncRequestState.postValue(newSyncRequestState) } /** * Create a rootTask. */ - fun startRoot(initSyncStep: InitSyncStep, - totalProgress: Int) { + fun startRoot( + initialSyncStep: InitialSyncStep, + totalProgress: Int + ) { endAll() - rootTask = TaskInfo(initSyncStep, totalProgress, null, 1F) + rootTask = TaskInfo(initialSyncStep, totalProgress, null, 1F) reportProgress(0F) } /** * Add a child to the leaf. */ - override fun startTask(initSyncStep: InitSyncStep, - totalProgress: Int, - parentWeight: Float) { + override fun startTask( + initialSyncStep: InitialSyncStep, + totalProgress: Int, + parentWeight: Float + ) { val currentLeaf = rootTask?.leaf() ?: return currentLeaf.child = TaskInfo( - initSyncStep = initSyncStep, + initialSyncStep = initialSyncStep, totalProgress = totalProgress, parent = currentLeaf, parentWeight = parentWeight @@ -72,7 +71,7 @@ internal class DefaultSyncStatusService @Inject constructor() : // Update the progress of the leaf and all its parents leaf.setProgress(progress) // Then update the live data using leaf wording and root progress - status.postValue(SyncStatusService.Status.InitialSyncProgressing(leaf.initSyncStep, root.currentProgress.toInt())) + syncRequestState.postValue(SyncRequestState.InitialSyncProgressing(leaf.initialSyncStep, root.currentProgress.toInt())) } } } @@ -87,13 +86,13 @@ internal class DefaultSyncStatusService @Inject constructor() : // And close it endedTask.parent.child = null } else { - status.postValue(SyncStatusService.Status.Idle) + syncRequestState.postValue(SyncRequestState.Idle) } } } fun endAll() { rootTask = null - status.postValue(SyncStatusService.Status.Idle) + syncRequestState.postValue(SyncRequestState.Idle) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt index 02a7a9a37fe13aef18d645a7e732b530c0cbb5a2..9e5302222ab3571e9c7964ce58752538874eb223 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt @@ -18,9 +18,9 @@ package org.matrix.android.sdk.internal.session.sync import androidx.work.ExistingPeriodicWorkPolicy import com.zhuinden.monarchy.Monarchy -import org.matrix.android.sdk.api.session.initsync.InitSyncStep import org.matrix.android.sdk.api.session.pushrules.PushRuleService import org.matrix.android.sdk.api.session.pushrules.RuleScope +import org.matrix.android.sdk.api.session.sync.InitialSyncStep import org.matrix.android.sdk.api.session.sync.model.GroupsSyncResponse import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse import org.matrix.android.sdk.api.session.sync.model.SyncResponse @@ -32,8 +32,6 @@ import org.matrix.android.sdk.internal.di.WorkManagerProvider import org.matrix.android.sdk.internal.session.SessionListeners import org.matrix.android.sdk.internal.session.dispatchTo import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker -import org.matrix.android.sdk.internal.session.initsync.ProgressReporter -import org.matrix.android.sdk.internal.session.initsync.reportSubtask import org.matrix.android.sdk.internal.session.pushrules.ProcessEventForPushTask import org.matrix.android.sdk.internal.session.sync.handler.CryptoSyncHandler import org.matrix.android.sdk.internal.session.sync.handler.GroupSyncHandler @@ -68,9 +66,11 @@ internal class SyncResponseHandler @Inject constructor( private val presenceSyncHandler: PresenceSyncHandler ) { - suspend fun handleResponse(syncResponse: SyncResponse, - fromToken: String?, - reporter: ProgressReporter?) { + suspend fun handleResponse( + syncResponse: SyncResponse, + fromToken: String?, + reporter: ProgressReporter? + ) { val isInitialSync = fromToken == null Timber.v("Start handling sync, is InitialSync: $isInitialSync") @@ -88,7 +88,7 @@ internal class SyncResponseHandler @Inject constructor( // to ensure to decrypt them properly measureTimeMillis { Timber.v("Handle toDevice") - reportSubtask(reporter, InitSyncStep.ImportingAccountCrypto, 100, 0.1f) { + reportSubtask(reporter, InitialSyncStep.ImportingAccountCrypto, 100, 0.1f) { if (syncResponse.toDevice != null) { cryptoSyncHandler.handleToDevice(syncResponse.toDevice, reporter) } @@ -109,7 +109,7 @@ internal class SyncResponseHandler @Inject constructor( // IMPORTANT nothing should be suspend here as we are accessing the realm instance (thread local) measureTimeMillis { Timber.v("Handle rooms") - reportSubtask(reporter, InitSyncStep.ImportingAccountRoom, 1, 0.7f) { + reportSubtask(reporter, InitialSyncStep.ImportingAccountRoom, 1, 0.7f) { if (syncResponse.rooms != null) { roomSyncHandler.handle(realm, syncResponse.rooms, isInitialSync, aggregator, reporter) } @@ -119,7 +119,7 @@ internal class SyncResponseHandler @Inject constructor( } measureTimeMillis { - reportSubtask(reporter, InitSyncStep.ImportingAccountGroups, 1, 0.1f) { + reportSubtask(reporter, InitialSyncStep.ImportingAccountGroups, 1, 0.1f) { Timber.v("Handle groups") if (syncResponse.groups != null) { groupSyncHandler.handle(realm, syncResponse.groups, reporter) @@ -130,7 +130,7 @@ internal class SyncResponseHandler @Inject constructor( } measureTimeMillis { - reportSubtask(reporter, InitSyncStep.ImportingAccountData, 1, 0.1f) { + reportSubtask(reporter, InitialSyncStep.ImportingAccountData, 1, 0.1f) { Timber.v("Handle accountData") userAccountDataSyncHandler.handle(realm, syncResponse.accountData) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt index f88d9731015b2fc504ceda7e0b0782a82532a264..ea296d379ddc51feb783eb8f1f3e14b98b3218a7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncTask.kt @@ -21,10 +21,10 @@ import okhttp3.ResponseBody import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.session.initsync.InitSyncStep -import org.matrix.android.sdk.api.session.initsync.SyncStatusService import org.matrix.android.sdk.api.session.statistics.StatisticEvent +import org.matrix.android.sdk.api.session.sync.InitialSyncStep import org.matrix.android.sdk.api.session.sync.InitialSyncStrategy +import org.matrix.android.sdk.api.session.sync.SyncRequestState import org.matrix.android.sdk.api.session.sync.initialSyncStrategy import org.matrix.android.sdk.api.session.sync.model.LazyRoomSyncEphemeral import org.matrix.android.sdk.api.session.sync.model.SyncResponse @@ -38,8 +38,6 @@ import org.matrix.android.sdk.internal.session.SessionListeners import org.matrix.android.sdk.internal.session.dispatchTo import org.matrix.android.sdk.internal.session.filter.FilterRepository import org.matrix.android.sdk.internal.session.homeserver.GetHomeServerCapabilitiesTask -import org.matrix.android.sdk.internal.session.initsync.DefaultSyncStatusService -import org.matrix.android.sdk.internal.session.initsync.reportSubtask import org.matrix.android.sdk.internal.session.sync.parsing.InitialSyncResponseParser import org.matrix.android.sdk.internal.session.user.UserStore import org.matrix.android.sdk.internal.task.Task @@ -68,7 +66,7 @@ internal class DefaultSyncTask @Inject constructor( @UserId private val userId: String, private val filterRepository: FilterRepository, private val syncResponseHandler: SyncResponseHandler, - private val defaultSyncStatusService: DefaultSyncStatusService, + private val syncRequestStateTracker: SyncRequestStateTracker, private val syncTokenStore: SyncTokenStore, private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask, private val userStore: UserStore, @@ -115,7 +113,7 @@ internal class DefaultSyncTask @Inject constructor( displayName = user?.displayName, avatarUrl = user?.avatarUrl ) - defaultSyncStatusService.startRoot(InitSyncStep.ImportingAccount, 100) + syncRequestStateTracker.startRoot(InitialSyncStep.ImportingAccount, 100) } // Maybe refresh the homeserver capabilities data we know getHomeServerCapabilitiesTask.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false)) @@ -132,7 +130,7 @@ internal class DefaultSyncTask @Inject constructor( roomSyncEphemeralTemporaryStore.reset() workingDir.mkdirs() val file = downloadInitSyncResponse(requestParams, syncStatisticsData) - syncResponseToReturn = reportSubtask(defaultSyncStatusService, InitSyncStep.ImportingAccount, 1, 0.7F) { + syncResponseToReturn = reportSubtask(syncRequestStateTracker, InitialSyncStep.ImportingAccount, 1, 0.7F) { handleSyncFile(file, initSyncStrategy) } // Delete all files @@ -150,15 +148,15 @@ internal class DefaultSyncTask @Inject constructor( syncStatisticsData.requestInitSyncTime = SystemClock.elapsedRealtime() syncStatisticsData.downloadInitSyncTime = syncStatisticsData.requestInitSyncTime logDuration("INIT_SYNC Database insertion", loggerTag, clock) { - syncResponseHandler.handleResponse(syncResponse, token, defaultSyncStatusService) + syncResponseHandler.handleResponse(syncResponse, token, syncRequestStateTracker) } syncResponseToReturn = syncResponse } } - defaultSyncStatusService.endAll() + syncRequestStateTracker.endAll() } else { Timber.tag(loggerTag.value).d("Start incremental sync request with since token $token") - defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncIdle) + syncRequestStateTracker.setSyncRequestState(SyncRequestState.IncrementalSyncIdle) val syncResponse = try { executeRequest(globalErrorReceiver) { syncAPI.sync( @@ -168,7 +166,7 @@ internal class DefaultSyncTask @Inject constructor( } } catch (throwable: Throwable) { Timber.tag(loggerTag.value).e(throwable, "Incremental sync request error") - defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncError) + syncRequestStateTracker.setSyncRequestState(SyncRequestState.IncrementalSyncError) throw throwable } val nbRooms = syncResponse.rooms?.invite.orEmpty().size + syncResponse.rooms?.join.orEmpty().size + syncResponse.rooms?.leave.orEmpty().size @@ -177,8 +175,8 @@ internal class DefaultSyncTask @Inject constructor( Timber.tag(loggerTag.value).d( "Incremental sync request parsing, $nbRooms room(s) $nbToDevice toDevice(s). Got nextBatch: $nextBatch" ) - defaultSyncStatusService.setStatus( - SyncStatusService.Status.IncrementalSyncParsing( + syncRequestStateTracker.setSyncRequestState( + SyncRequestState.IncrementalSyncParsing( rooms = nbRooms, toDevice = nbToDevice ) @@ -186,7 +184,7 @@ internal class DefaultSyncTask @Inject constructor( syncResponseHandler.handleResponse(syncResponse, token, null) syncResponseToReturn = syncResponse Timber.tag(loggerTag.value).d("Incremental sync done") - defaultSyncStatusService.setStatus(SyncStatusService.Status.IncrementalSyncDone) + syncRequestStateTracker.setSyncRequestState(SyncRequestState.IncrementalSyncDone) } syncStatisticsData.treatmentSyncTime = SystemClock.elapsedRealtime() syncStatisticsData.nbOfRooms = syncResponseToReturn?.rooms?.join?.size ?: 0 @@ -201,20 +199,20 @@ internal class DefaultSyncTask @Inject constructor( val status = initialSyncStatusRepository.getStep() if (workingFile.exists() && status >= InitialSyncStatus.STEP_DOWNLOADED) { Timber.tag(loggerTag.value).d("INIT_SYNC file is already here") - reportSubtask(defaultSyncStatusService, InitSyncStep.Downloading, 1, 0.3f) { + reportSubtask(syncRequestStateTracker, InitialSyncStep.Downloading, 1, 0.3f) { // Empty task } } else { initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_DOWNLOADING) val syncResponse = logDuration("INIT_SYNC Perform server request", loggerTag, clock) { - reportSubtask(defaultSyncStatusService, InitSyncStep.ServerComputing, 1, 0.2f) { + reportSubtask(syncRequestStateTracker, InitialSyncStep.ServerComputing, 1, 0.2f) { getSyncResponse(requestParams, MAX_NUMBER_OF_RETRY_AFTER_TIMEOUT) } } syncStatisticsData.requestInitSyncTime = SystemClock.elapsedRealtime() if (syncResponse.isSuccessful) { logDuration("INIT_SYNC Download and save to file", loggerTag, clock) { - reportSubtask(defaultSyncStatusService, InitSyncStep.Downloading, 1, 0.1f) { + reportSubtask(syncRequestStateTracker, InitialSyncStep.Downloading, 1, 0.1f) { syncResponse.body()?.byteStream()?.use { inputStream -> workingFile.outputStream().use { outputStream -> inputStream.copyTo(outputStream) @@ -263,7 +261,7 @@ internal class DefaultSyncTask @Inject constructor( Timber.tag(loggerTag.value).d("INIT_SYNC $nbOfJoinedRooms rooms, $nbOfJoinedRoomsInFile ephemeral stored into files") logDuration("INIT_SYNC Database insertion", loggerTag, clock) { - syncResponseHandler.handleResponse(syncResponse, null, defaultSyncStatusService) + syncResponseHandler.handleResponse(syncResponse, null, syncRequestStateTracker) } initialSyncStatusRepository.setStep(InitialSyncStatus.STEP_SUCCESS) syncResponse diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/TaskInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/TaskInfo.kt similarity index 81% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/TaskInfo.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/TaskInfo.kt index fef16bf1d773492b7054901a4101c41434bc7482..7032aae2b2021e8c36e6d7eecfea0b217ce685ec 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/initsync/TaskInfo.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/TaskInfo.kt @@ -14,15 +14,17 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.session.initsync +package org.matrix.android.sdk.internal.session.sync -import org.matrix.android.sdk.api.session.initsync.InitSyncStep +import org.matrix.android.sdk.api.session.sync.InitialSyncStep import timber.log.Timber -internal class TaskInfo(val initSyncStep: InitSyncStep, - val totalProgress: Int, - val parent: TaskInfo?, - val parentWeight: Float) { +internal class TaskInfo( + val initialSyncStep: InitialSyncStep, + val totalProgress: Int, + val parent: TaskInfo?, + val parentWeight: Float +) { var child: TaskInfo? = null var currentProgress = 0F private set diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt index dd9576216649bac3d7129c941e64646b05b4d12c..b6142b3a7aef7192deb59982d3f1f67fa90d5e88 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt @@ -29,14 +29,16 @@ import org.matrix.android.sdk.api.session.sync.model.SyncResponse import org.matrix.android.sdk.api.session.sync.model.ToDeviceSyncResponse import org.matrix.android.sdk.internal.crypto.DefaultCryptoService import org.matrix.android.sdk.internal.crypto.verification.DefaultVerificationService -import org.matrix.android.sdk.internal.session.initsync.ProgressReporter +import org.matrix.android.sdk.internal.session.sync.ProgressReporter import timber.log.Timber import javax.inject.Inject private val loggerTag = LoggerTag("CryptoSyncHandler", LoggerTag.CRYPTO) -internal class CryptoSyncHandler @Inject constructor(private val cryptoService: DefaultCryptoService, - private val verificationService: DefaultVerificationService) { +internal class CryptoSyncHandler @Inject constructor( + private val cryptoService: DefaultCryptoService, + private val verificationService: DefaultVerificationService +) { suspend fun handleToDevice(toDevice: ToDeviceSyncResponse, progressReporter: ProgressReporter? = null) { val total = toDevice.events?.size ?: 0 @@ -62,7 +64,7 @@ internal class CryptoSyncHandler @Inject constructor(private val cryptoService: /** * Decrypt an encrypted event. * - * @param event the event to decrypt + * @param event the event to decrypt * @param timelineId the timeline identifier * @return true if the event has been decrypted */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/GroupSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/GroupSyncHandler.kt index 552462e25e69e451edd1533a8451db14a5897701..1983d9f433576e1ff5bd124e33b2a0b54c0de460 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/GroupSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/GroupSyncHandler.kt @@ -17,16 +17,16 @@ package org.matrix.android.sdk.internal.session.sync.handler import io.realm.Realm -import org.matrix.android.sdk.api.session.initsync.InitSyncStep import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.sync.InitialSyncStep import org.matrix.android.sdk.api.session.sync.model.GroupsSyncResponse import org.matrix.android.sdk.api.session.sync.model.InvitedGroupSync import org.matrix.android.sdk.internal.database.model.GroupEntity import org.matrix.android.sdk.internal.database.model.GroupSummaryEntity import org.matrix.android.sdk.internal.database.query.getOrCreate import org.matrix.android.sdk.internal.database.query.where -import org.matrix.android.sdk.internal.session.initsync.ProgressReporter -import org.matrix.android.sdk.internal.session.initsync.mapWithProgress +import org.matrix.android.sdk.internal.session.sync.ProgressReporter +import org.matrix.android.sdk.internal.session.sync.mapWithProgress import javax.inject.Inject internal class GroupSyncHandler @Inject constructor() { @@ -37,9 +37,11 @@ internal class GroupSyncHandler @Inject constructor() { data class LEFT(val data: Map<String, Any>) : HandlingStrategy() } - fun handle(realm: Realm, - roomsSyncResponse: GroupsSyncResponse, - reporter: ProgressReporter? = null) { + fun handle( + realm: Realm, + roomsSyncResponse: GroupsSyncResponse, + reporter: ProgressReporter? = null + ) { handleGroupSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), reporter) handleGroupSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), reporter) handleGroupSync(realm, HandlingStrategy.LEFT(roomsSyncResponse.leave), reporter) @@ -49,26 +51,28 @@ internal class GroupSyncHandler @Inject constructor() { private fun handleGroupSync(realm: Realm, handlingStrategy: HandlingStrategy, reporter: ProgressReporter?) { val groups = when (handlingStrategy) { - is HandlingStrategy.JOINED -> - handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountGroups, 0.6f) { + is HandlingStrategy.JOINED -> + handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountGroups, 0.6f) { handleJoinedGroup(realm, it.key) } is HandlingStrategy.INVITED -> - handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountGroups, 0.3f) { + handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountGroups, 0.3f) { handleInvitedGroup(realm, it.key) } - is HandlingStrategy.LEFT -> - handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountGroups, 0.1f) { + is HandlingStrategy.LEFT -> + handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountGroups, 0.1f) { handleLeftGroup(realm, it.key) } } realm.insertOrUpdate(groups) } - private fun handleJoinedGroup(realm: Realm, - groupId: String): GroupEntity { + private fun handleJoinedGroup( + realm: Realm, + groupId: String + ): GroupEntity { val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupId) groupEntity.membership = Membership.JOIN @@ -76,8 +80,10 @@ internal class GroupSyncHandler @Inject constructor() { return groupEntity } - private fun handleInvitedGroup(realm: Realm, - groupId: String): GroupEntity { + private fun handleInvitedGroup( + realm: Realm, + groupId: String + ): GroupEntity { val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupId) groupEntity.membership = Membership.INVITE @@ -85,8 +91,10 @@ internal class GroupSyncHandler @Inject constructor() { return groupEntity } - private fun handleLeftGroup(realm: Realm, - groupId: String): GroupEntity { + private fun handleLeftGroup( + realm: Realm, + groupId: String + ): GroupEntity { val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupId) groupEntity.membership = Membership.LEAVE diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt index c213ea4bcfdbac5a68f5b19ab46e4b98cc4513c9..0f296ded5d31173a6e92ff629674c29db53c1765 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt @@ -84,10 +84,10 @@ internal class UserAccountDataSyncHandler @Inject constructor( // Generic handling, just save in base handleGenericAccountData(realm, event.type, event.content) when (event.type) { - UserAccountDataTypes.TYPE_DIRECT_MESSAGES -> handleDirectChatRooms(realm, event) - UserAccountDataTypes.TYPE_PUSH_RULES -> handlePushRules(realm, event) + UserAccountDataTypes.TYPE_DIRECT_MESSAGES -> handleDirectChatRooms(realm, event) + UserAccountDataTypes.TYPE_PUSH_RULES -> handlePushRules(realm, event) UserAccountDataTypes.TYPE_IGNORED_USER_LIST -> handleIgnoredUsers(realm, event) - UserAccountDataTypes.TYPE_BREADCRUMBS -> handleBreadcrumbs(realm, event) + UserAccountDataTypes.TYPE_BREADCRUMBS -> handleBreadcrumbs(realm, event) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ReadReceiptHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ReadReceiptHandler.kt index 77bee18df932814a3bab3fbbcdf2f11712cf90dc..7329611a01776e50577334842457a40bff73ded7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ReadReceiptHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ReadReceiptHandler.kt @@ -44,9 +44,11 @@ internal class ReadReceiptHandler @Inject constructor( companion object { - fun createContent(userId: String, - eventId: String, - currentTimeMillis: Long): ReadReceiptContent { + fun createContent( + userId: String, + eventId: String, + currentTimeMillis: Long + ): ReadReceiptContent { return mapOf( eventId to mapOf( READ_KEY to mapOf( @@ -59,11 +61,13 @@ internal class ReadReceiptHandler @Inject constructor( } } - fun handle(realm: Realm, - roomId: String, - content: ReadReceiptContent?, - isInitialSync: Boolean, - aggregator: SyncResponsePostTreatmentAggregator?) { + fun handle( + realm: Realm, + roomId: String, + content: ReadReceiptContent?, + isInitialSync: Boolean, + aggregator: SyncResponsePostTreatmentAggregator? + ) { content ?: return try { @@ -73,11 +77,13 @@ internal class ReadReceiptHandler @Inject constructor( } } - private fun handleReadReceiptContent(realm: Realm, - roomId: String, - content: ReadReceiptContent, - isInitialSync: Boolean, - aggregator: SyncResponsePostTreatmentAggregator?) { + private fun handleReadReceiptContent( + realm: Realm, + roomId: String, + content: ReadReceiptContent, + isInitialSync: Boolean, + aggregator: SyncResponsePostTreatmentAggregator? + ) { if (isInitialSync) { initialSyncStrategy(realm, roomId, content) } else { @@ -101,10 +107,12 @@ internal class ReadReceiptHandler @Inject constructor( realm.insertOrUpdate(readReceiptSummaries) } - private fun incrementalSyncStrategy(realm: Realm, - roomId: String, - content: ReadReceiptContent, - aggregator: SyncResponsePostTreatmentAggregator?) { + private fun incrementalSyncStrategy( + realm: Realm, + roomId: String, + content: ReadReceiptContent, + aggregator: SyncResponsePostTreatmentAggregator? + ) { // First check if we have data from init sync to handle getContentFromInitSync(roomId)?.let { Timber.w("INIT_SYNC Insert during incremental sync RR for room $roomId") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt index c5d14afac0096ac9afb401b81f2a7e8ca172ead0..f99fe964102fa06a7ad9bacc93f9d1625e68af3f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt @@ -27,11 +27,11 @@ import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService -import org.matrix.android.sdk.api.session.initsync.InitSyncStep import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.threads.model.ThreadSummaryUpdateType +import org.matrix.android.sdk.api.session.sync.InitialSyncStep import org.matrix.android.sdk.api.session.sync.InitialSyncStrategy import org.matrix.android.sdk.api.session.sync.initialSyncStrategy import org.matrix.android.sdk.api.session.sync.model.InvitedRoomSync @@ -57,6 +57,7 @@ import org.matrix.android.sdk.internal.database.model.deleteOnCascade import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore import org.matrix.android.sdk.internal.database.query.find +import org.matrix.android.sdk.internal.database.query.findAll import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfThread import org.matrix.android.sdk.internal.database.query.getOrCreate @@ -67,17 +68,17 @@ import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.extensions.clearWith import org.matrix.android.sdk.internal.session.StreamEventsManager import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent -import org.matrix.android.sdk.internal.session.initsync.ProgressReporter -import org.matrix.android.sdk.internal.session.initsync.mapWithProgress -import org.matrix.android.sdk.internal.session.initsync.reportSubtask import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembershipStateDataSource import org.matrix.android.sdk.internal.session.room.membership.RoomMemberEventHandler import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection import org.matrix.android.sdk.internal.session.room.timeline.TimelineInput import org.matrix.android.sdk.internal.session.room.typing.TypingEventContent +import org.matrix.android.sdk.internal.session.sync.ProgressReporter import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator +import org.matrix.android.sdk.internal.session.sync.mapWithProgress import org.matrix.android.sdk.internal.session.sync.parsing.RoomSyncAccountDataHandler +import org.matrix.android.sdk.internal.session.sync.reportSubtask import org.matrix.android.sdk.internal.util.computeBestChunkSize import org.matrix.android.sdk.internal.util.time.Clock import timber.log.Timber @@ -106,11 +107,13 @@ internal class RoomSyncHandler @Inject constructor( data class LEFT(val data: Map<String, RoomSync>) : HandlingStrategy() } - fun handle(realm: Realm, - roomsSyncResponse: RoomsSyncResponse, - isInitialSync: Boolean, - aggregator: SyncResponsePostTreatmentAggregator, - reporter: ProgressReporter? = null) { + fun handle( + realm: Realm, + roomsSyncResponse: RoomsSyncResponse, + isInitialSync: Boolean, + aggregator: SyncResponsePostTreatmentAggregator, + reporter: ProgressReporter? = null + ) { handleRoomSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), isInitialSync, aggregator, reporter) handleRoomSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), isInitialSync, aggregator, reporter) handleRoomSync(realm, HandlingStrategy.LEFT(roomsSyncResponse.leave), isInitialSync, aggregator, reporter) @@ -124,11 +127,13 @@ internal class RoomSyncHandler @Inject constructor( } // PRIVATE METHODS ***************************************************************************** - private fun handleRoomSync(realm: Realm, - handlingStrategy: HandlingStrategy, - isInitialSync: Boolean, - aggregator: SyncResponsePostTreatmentAggregator, - reporter: ProgressReporter?) { + private fun handleRoomSync( + realm: Realm, + handlingStrategy: HandlingStrategy, + isInitialSync: Boolean, + aggregator: SyncResponsePostTreatmentAggregator, + reporter: ProgressReporter? + ) { val insertType = if (isInitialSync) { EventInsertType.INITIAL_SYNC } else { @@ -136,24 +141,24 @@ internal class RoomSyncHandler @Inject constructor( } val syncLocalTimeStampMillis = clock.epochMillis() val rooms = when (handlingStrategy) { - is HandlingStrategy.JOINED -> { + is HandlingStrategy.JOINED -> { if (isInitialSync && initialSyncStrategy is InitialSyncStrategy.Optimized) { insertJoinRoomsFromInitSync(realm, handlingStrategy, syncLocalTimeStampMillis, aggregator, reporter) // Rooms are already inserted, return an empty list emptyList() } else { - handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountJoinedRooms, 0.6f) { + handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountJoinedRooms, 0.6f) { handleJoinedRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis, aggregator) } } } is HandlingStrategy.INVITED -> - handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountInvitedRooms, 0.1f) { + handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountInvitedRooms, 0.1f) { handleInvitedRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis) } - is HandlingStrategy.LEFT -> { - handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountLeftRooms, 0.3f) { + is HandlingStrategy.LEFT -> { + handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountLeftRooms, 0.3f) { handleLeftRoom(realm, it.key, it.value, insertType, syncLocalTimeStampMillis) } } @@ -161,18 +166,20 @@ internal class RoomSyncHandler @Inject constructor( realm.insertOrUpdate(rooms) } - private fun insertJoinRoomsFromInitSync(realm: Realm, - handlingStrategy: HandlingStrategy.JOINED, - syncLocalTimeStampMillis: Long, - aggregator: SyncResponsePostTreatmentAggregator, - reporter: ProgressReporter?) { + private fun insertJoinRoomsFromInitSync( + realm: Realm, + handlingStrategy: HandlingStrategy.JOINED, + syncLocalTimeStampMillis: Long, + aggregator: SyncResponsePostTreatmentAggregator, + reporter: ProgressReporter? + ) { val bestChunkSize = computeBestChunkSize( listSize = handlingStrategy.data.keys.size, limit = (initialSyncStrategy as? InitialSyncStrategy.Optimized)?.maxRoomsToInsert ?: Int.MAX_VALUE ) if (bestChunkSize.shouldChunk()) { - reportSubtask(reporter, InitSyncStep.ImportingAccountJoinedRooms, bestChunkSize.numberOfChunks, 0.6f) { + reportSubtask(reporter, InitialSyncStep.ImportingAccountJoinedRooms, bestChunkSize.numberOfChunks, 0.6f) { Timber.d("INIT_SYNC ${handlingStrategy.data.keys.size} rooms to insert, split with $bestChunkSize") // I cannot find a better way to chunk a map, so chunk the keys and then create new maps handlingStrategy.data.keys @@ -196,19 +203,21 @@ internal class RoomSyncHandler @Inject constructor( } } else { // No need to split - val rooms = handlingStrategy.data.mapWithProgress(reporter, InitSyncStep.ImportingAccountJoinedRooms, 0.6f) { + val rooms = handlingStrategy.data.mapWithProgress(reporter, InitialSyncStep.ImportingAccountJoinedRooms, 0.6f) { handleJoinedRoom(realm, it.key, it.value, EventInsertType.INITIAL_SYNC, syncLocalTimeStampMillis, aggregator) } realm.insertOrUpdate(rooms) } } - private fun handleJoinedRoom(realm: Realm, - roomId: String, - roomSync: RoomSync, - insertType: EventInsertType, - syncLocalTimestampMillis: Long, - aggregator: SyncResponsePostTreatmentAggregator): RoomEntity { + private fun handleJoinedRoom( + realm: Realm, + roomId: String, + roomSync: RoomSync, + insertType: EventInsertType, + syncLocalTimestampMillis: Long, + aggregator: SyncResponsePostTreatmentAggregator + ): RoomEntity { Timber.v("Handle join sync for room $roomId") val isInitialSync = insertType == EventInsertType.INITIAL_SYNC @@ -281,11 +290,13 @@ internal class RoomSyncHandler @Inject constructor( return roomEntity } - private fun handleInvitedRoom(realm: Realm, - roomId: String, - roomSync: InvitedRoomSync, - insertType: EventInsertType, - syncLocalTimestampMillis: Long): RoomEntity { + private fun handleInvitedRoom( + realm: Realm, + roomId: String, + roomSync: InvitedRoomSync, + insertType: EventInsertType, + syncLocalTimestampMillis: Long + ): RoomEntity { Timber.v("Handle invited sync for room $roomId") val isInitialSync = insertType == EventInsertType.INITIAL_SYNC val roomEntity = RoomEntity.getOrCreate(realm, roomId) @@ -312,11 +323,13 @@ internal class RoomSyncHandler @Inject constructor( return roomEntity } - private fun handleLeftRoom(realm: Realm, - roomId: String, - roomSync: RoomSync, - insertType: EventInsertType, - syncLocalTimestampMillis: Long): RoomEntity { + private fun handleLeftRoom( + realm: Realm, + roomId: String, + roomSync: RoomSync, + insertType: EventInsertType, + syncLocalTimestampMillis: Long + ): RoomEntity { val isInitialSync = insertType == EventInsertType.INITIAL_SYNC val roomEntity = RoomEntity.getOrCreate(realm, roomId) for (event in roomSync.state?.events.orEmpty()) { @@ -357,22 +370,25 @@ internal class RoomSyncHandler @Inject constructor( return roomEntity } - private fun handleTimelineEvents(realm: Realm, - roomId: String, - roomEntity: RoomEntity, - eventList: List<Event>, - prevToken: String? = null, - isLimited: Boolean = true, - insertType: EventInsertType, - syncLocalTimestampMillis: Long, - aggregator: SyncResponsePostTreatmentAggregator): ChunkEntity { + private fun handleTimelineEvents( + realm: Realm, + roomId: String, + roomEntity: RoomEntity, + eventList: List<Event>, + prevToken: String? = null, + isLimited: Boolean = true, + insertType: EventInsertType, + syncLocalTimestampMillis: Long, + aggregator: SyncResponsePostTreatmentAggregator + ): ChunkEntity { val lastChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomEntity.roomId) - if (isLimited && lastChunk != null) { - lastChunk.deleteOnCascade(deleteStateEvents = false, canDeleteRoot = true) - } val chunkEntity = if (!isLimited && lastChunk != null) { lastChunk } else { + // Delete all chunks of the room in case of gap. + ChunkEntity.findAll(realm, roomId).forEach { + it.deleteOnCascade(deleteStateEvents = false, canDeleteRoot = true) + } realm.createObject<ChunkEntity>().apply { this.prevToken = prevToken this.isLastForward = true @@ -500,11 +516,13 @@ internal class RoomSyncHandler @Inject constructor( * Adds new event to the appropriate thread chunk. If the event is already in * the thread timeline and /relations api, we should not added it */ - private fun addToThreadChunkIfNeeded(realm: Realm, - roomId: String, - threadId: String, - timelineEventEntity: TimelineEventEntity?, - roomEntity: RoomEntity) { + private fun addToThreadChunkIfNeeded( + realm: Realm, + roomId: String, + threadId: String, + timelineEventEntity: TimelineEventEntity?, + roomEntity: RoomEntity + ) { val eventId = timelineEventEntity?.eventId ?: return ChunkEntity.findLastForwardChunkOfThread(realm, roomId, threadId)?.let { threadChunk -> @@ -520,9 +538,10 @@ internal class RoomSyncHandler @Inject constructor( private fun decryptIfNeeded(event: Event, roomId: String) { try { + val timelineId = generateTimelineId(roomId) // Event from sync does not have roomId, so add it to the event first // note: runBlocking should be used here while we are in realm single thread executor, to avoid thread switching - val result = runBlocking { cryptoService.decryptEvent(event.copy(roomId = roomId), "") } + val result = runBlocking { cryptoService.decryptEvent(event.copy(roomId = roomId), timelineId) } event.mxDecryptionResult = OlmDecryptionResult( payload = result.clearEvent, senderKey = result.senderCurve25519Key, @@ -537,15 +556,21 @@ internal class RoomSyncHandler @Inject constructor( } } + private fun generateTimelineId(roomId: String): String { + return "RoomSyncHandler$roomId" + } + data class EphemeralResult( val typingUserIds: List<String> = emptyList() ) - private fun handleEphemeral(realm: Realm, - roomId: String, - ephemeralEvents: List<Event>, - isInitialSync: Boolean, - aggregator: SyncResponsePostTreatmentAggregator): EphemeralResult { + private fun handleEphemeral( + realm: Realm, + roomId: String, + ephemeralEvents: List<Event>, + isInitialSync: Boolean, + aggregator: SyncResponsePostTreatmentAggregator + ): EphemeralResult { var result = EphemeralResult() for (event in ephemeralEvents) { when (event.type) { @@ -555,12 +580,12 @@ internal class RoomSyncHandler @Inject constructor( readReceiptHandler.handle(realm, roomId, readReceiptContent, isInitialSync, aggregator) } } - EventType.TYPING -> { + EventType.TYPING -> { event.content.toModel<TypingEventContent>()?.let { typingEventContent -> result = result.copy(typingUserIds = typingEventContent.typingUserIds) } } - else -> Timber.w("Ephemeral event type '${event.type}' not yet supported") + else -> Timber.w("Ephemeral event type '${event.type}' not yet supported") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomTypingUsersHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomTypingUsersHandler.kt index 63db13a5b804871163c24174c532bc3fdbfac4e4..54bb63753c9cacb5d4ada425bf993cd3095288ca 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomTypingUsersHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomTypingUsersHandler.kt @@ -23,8 +23,10 @@ import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper import org.matrix.android.sdk.internal.session.typing.DefaultTypingUsersTracker import javax.inject.Inject -internal class RoomTypingUsersHandler @Inject constructor(@UserId private val userId: String, - private val typingUsersTracker: DefaultTypingUsersTracker) { +internal class RoomTypingUsersHandler @Inject constructor( + @UserId private val userId: String, + private val typingUsersTracker: DefaultTypingUsersTracker +) { // TODO This could be handled outside of the Realm transaction. Use the new aggregator? fun handle(realm: Realm, roomId: String, ephemeralResult: RoomSyncHandler.EphemeralResult?) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ThreadsAwarenessHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ThreadsAwarenessHandler.kt index 03e076c217726f29c2d0ebffb36b04b55a9c3349..8c7557a5b8611f156d8f970457fc0c2e79ea584f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ThreadsAwarenessHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ThreadsAwarenessHandler.kt @@ -156,10 +156,12 @@ internal class ThreadsAwarenessHandler @Inject constructor( * Handle events mainly coming from the RoomSyncHandler. * @return The content to inject in the roomSyncHandler live events */ - fun makeEventThreadAware(realm: Realm, - roomId: String?, - event: Event?, - eventEntity: EventEntity? = null): String? { + fun makeEventThreadAware( + realm: Realm, + roomId: String?, + event: Event?, + eventEntity: EventEntity? = null + ): String? { event ?: return null roomId ?: return null if (lightweightSettingsStorage.areThreadMessagesEnabled() && !isReplyEvent(event)) return null @@ -206,6 +208,8 @@ internal class ThreadsAwarenessHandler @Inject constructor( /** * Handle for not thread events that we have marked them as root. * Find relations and inject them accordingly + * @param realm the realm instance + * @param roomId the current room Id * @param eventEntity the current eventEntity received * @param event the current event received * @return The content to inject in the roomSyncHandler live events @@ -229,9 +233,12 @@ internal class ThreadsAwarenessHandler @Inject constructor( * This function is responsible to check if there is any event that relates to our current event. * This is useful when we receive an event that relates to a missing parent, so when later we receive the parent * we can update the child as well. + * @param realm the realm instance + * @param roomId the current room Id * @param event the current event that we examine * @param eventBody the current body of the event * @param isFromCache determines whether or not we already know this is root thread event + * @param threadRelation the information about thread * @return The content to inject in the roomSyncHandler live events */ private fun handleEventsThatRelatesTo( @@ -266,10 +273,12 @@ internal class ThreadsAwarenessHandler @Inject constructor( * Actual update the eventEntity with the new payload. * @return the content to inject when this is executed by RoomSyncHandler */ - private fun updateEventEntity(event: Event, - eventEntity: EventEntity?, - eventPayload: MutableMap<String, Any>, - messageTextContent: Content): String? { + private fun updateEventEntity( + event: Event, + eventEntity: EventEntity?, + eventPayload: MutableMap<String, Any>, + messageTextContent: Content + ): String? { eventPayload["content"] = messageTextContent if (event.isEncrypted()) { @@ -291,16 +300,20 @@ internal class ThreadsAwarenessHandler @Inject constructor( } /** - * Injecting $eventToInject decrypted content as a reply to $event. - * @param eventToInject the event that will inject + * Injecting [eventToInject] decrypted content as a reply to event. + * @param roomId the room id * @param eventBody the actual event body + * @param eventToInject the event that will inject + * @param eventToInjectBody the event body to inject + * @param threadRelation the information about thread * @return The final content with the injected event */ - private fun injectEvent(roomId: String, - eventBody: String, - eventToInject: Event, - eventToInjectBody: String, - threadRelation: RelationDefaultContent? + private fun injectEvent( + roomId: String, + eventBody: String, + eventToInject: Event, + eventToInjectBody: String, + threadRelation: RelationDefaultContent? ): Content? { val eventToInjectId = eventToInject.eventId ?: return null val eventIdToInjectSenderId = eventToInject.senderId.orEmpty() @@ -326,11 +339,13 @@ internal class ThreadsAwarenessHandler @Inject constructor( /** * Integrate fallback Quote reply. */ - private fun injectFallbackIndicator(event: Event, - eventBody: String, - eventEntity: EventEntity?, - eventPayload: MutableMap<String, Any>, - threadRelation: RelationDefaultContent?): String? { + private fun injectFallbackIndicator( + event: Event, + eventBody: String, + eventEntity: EventEntity?, + eventPayload: MutableMap<String, Any>, + threadRelation: RelationDefaultContent? + ): String? { val replyFormatted = LocalEchoEventFactory.QUOTE_PATTERN.format( "In reply to a thread", eventBody diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt index fc6a4e03d6410fb49e2884fef42a3459a70e791d..24a60a80da6ae50059dd3d619a2922b6db3c67fc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt @@ -56,11 +56,12 @@ private const val DEFAULT_LONG_POOL_TIMEOUT = 30_000L private val loggerTag = LoggerTag("SyncThread", LoggerTag.SYNC) -internal class SyncThread @Inject constructor(private val syncTask: SyncTask, - private val networkConnectivityChecker: NetworkConnectivityChecker, - private val backgroundDetectionObserver: BackgroundDetectionObserver, - private val activeCallHandler: ActiveCallHandler, - private val lightweightSettingsStorage: DefaultLightweightSettingsStorage +internal class SyncThread @Inject constructor( + private val syncTask: SyncTask, + private val networkConnectivityChecker: NetworkConnectivityChecker, + private val backgroundDetectionObserver: BackgroundDetectionObserver, + private val activeCallHandler: ActiveCallHandler, + private val lightweightSettingsStorage: DefaultLightweightSettingsStorage ) : Thread("SyncThread"), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener { private var state: SyncState = SyncState.Idle @@ -179,8 +180,8 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, val afterPause = state.let { it is SyncState.Running && it.afterPause } val timeout = when { previousSyncResponseHasToDevice -> 0L /* Force timeout to 0 */ - afterPause -> 0L /* No timeout after a pause */ - else -> DEFAULT_LONG_POOL_TIMEOUT + afterPause -> 0L /* No timeout after a pause */ + else -> DEFAULT_LONG_POOL_TIMEOUT } Timber.tag(loggerTag.value).d("Execute sync request with timeout $timeout") val presence = lightweightSettingsStorage.getSyncPresenceStatus() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt index bbb18b664c6bf43a72b9024c7f593a243800cad4..0cc7944d58c02eba1f173932d0254eb34cca9697 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncWorker.kt @@ -119,9 +119,11 @@ internal class SyncWorker(context: Context, workerParameters: WorkerParameters, companion object { private const val BG_SYNC_WORK_NAME = "BG_SYNCP" - fun requireBackgroundSync(workManagerProvider: WorkManagerProvider, - sessionId: String, - serverTimeoutInSeconds: Long = 0) { + fun requireBackgroundSync( + workManagerProvider: WorkManagerProvider, + sessionId: String, + serverTimeoutInSeconds: Long = 0 + ) { val data = WorkerParamsFactory.toData( Params( sessionId = sessionId, @@ -139,11 +141,13 @@ internal class SyncWorker(context: Context, workerParameters: WorkerParameters, .enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest) } - fun automaticallyBackgroundSync(workManagerProvider: WorkManagerProvider, - sessionId: String, - serverTimeoutInSeconds: Long = 0, - delayInSeconds: Long = 30, - forceImmediate: Boolean = false) { + fun automaticallyBackgroundSync( + workManagerProvider: WorkManagerProvider, + sessionId: String, + serverTimeoutInSeconds: Long = 0, + delayInSeconds: Long = 30, + forceImmediate: Boolean = false + ) { val data = WorkerParamsFactory.toData( Params( sessionId = sessionId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/TokensChunkResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/TokensChunkResponse.kt index 533ba70b054afa40b9e315bfef300ec2dc292115..40fdcbbb84c1732ece74cf5cc5342d57d7b28809 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/TokensChunkResponse.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/TokensChunkResponse.kt @@ -22,4 +22,5 @@ import com.squareup.moshi.JsonClass internal data class TokensChunkResponse<T>( val start: String? = null, val end: String? = null, - val chunk: List<T>? = null) + val chunk: List<T>? = null +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/parsing/RoomSyncAccountDataHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/parsing/RoomSyncAccountDataHandler.kt index 5e7bde87e77d2a668e1e9369331debe9ef283206..b1b2bfef339495fea94a6feff635322ba219a7eb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/parsing/RoomSyncAccountDataHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/parsing/RoomSyncAccountDataHandler.kt @@ -32,8 +32,10 @@ import org.matrix.android.sdk.internal.session.sync.handler.room.RoomFullyReadHa import org.matrix.android.sdk.internal.session.sync.handler.room.RoomTagHandler import javax.inject.Inject -internal class RoomSyncAccountDataHandler @Inject constructor(private val roomTagHandler: RoomTagHandler, - private val roomFullyReadHandler: RoomFullyReadHandler) { +internal class RoomSyncAccountDataHandler @Inject constructor( + private val roomTagHandler: RoomTagHandler, + private val roomFullyReadHandler: RoomFullyReadHandler +) { fun handle(realm: Realm, roomId: String, accountData: RoomSyncAccountData) { if (accountData.events.isNullOrEmpty()) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt index 9876643bed1a6c8ca3ff0c3ced398ef91183d11b..b687f5833af8300714b4ff92e873877d00105d96 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt @@ -51,8 +51,10 @@ internal class DefaultTermsService @Inject constructor( private val updateUserAccountDataTask: UpdateUserAccountDataTask ) : TermsService { - override suspend fun getTerms(serviceType: TermsService.ServiceType, - baseUrl: String): GetTermsResponse { + override suspend fun getTerms( + serviceType: TermsService.ServiceType, + baseUrl: String + ): GetTermsResponse { val url = buildUrl(baseUrl, serviceType) val termsResponse = executeRequest(null) { termsAPI.getTerms("${url}terms") @@ -90,10 +92,12 @@ internal class DefaultTermsService @Inject constructor( } } - override suspend fun agreeToTerms(serviceType: TermsService.ServiceType, - baseUrl: String, - agreedUrls: List<String>, - token: String?) { + override suspend fun agreeToTerms( + serviceType: TermsService.ServiceType, + baseUrl: String, + agreedUrls: List<String>, + token: String? + ) { val url = buildUrl(baseUrl, serviceType) val tokenToUse = token?.takeIf { it.isNotEmpty() } ?: getToken(baseUrl) @@ -128,7 +132,7 @@ internal class DefaultTermsService @Inject constructor( private fun buildUrl(baseUrl: String, serviceType: TermsService.ServiceType): String { val servicePath = when (serviceType) { TermsService.ServiceType.IntegrationManager -> NetworkConstants.URI_INTEGRATION_MANAGER_PATH - TermsService.ServiceType.IdentityService -> NetworkConstants.URI_IDENTITY_PATH_V2 + TermsService.ServiceType.IdentityService -> NetworkConstants.URI_IDENTITY_PATH_V2 } return "${baseUrl.ensureTrailingSlash()}$servicePath" } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt index f6f57bf0ef0919b0c4fc4dfbc720d9186c6ccf80..6a3328ee52468c735634098cf5e2577e6fedee71 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt @@ -37,15 +37,19 @@ internal interface TermsAPI { * This request requires authentication. */ @POST - suspend fun agreeToTerms(@Url url: String, - @Body params: AcceptTermsBody, - @Header(HttpHeaders.Authorization) token: String) + suspend fun agreeToTerms( + @Url url: String, + @Body params: AcceptTermsBody, + @Header(HttpHeaders.Authorization) token: String + ) /** * API to retrieve the terms for a homeserver. The API /terms does not exist yet, so retrieve the terms from the login flow. * We do not care about the result (Credentials). */ @POST - suspend fun register(@Url url: String, - @Body body: JsonDict = emptyJsonDict) + suspend fun register( + @Url url: String, + @Body body: JsonDict = emptyJsonDict + ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsModule.kt index d7b6f68add0399b87579444be5bb759f3a5118b7..06d12bfe76be9497de9f40e4e609d5e24170b096 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsModule.kt @@ -34,8 +34,10 @@ internal abstract class TermsModule { @Provides @JvmStatic @SessionScope - fun providesTermsAPI(@UnauthenticatedWithCertificate unauthenticatedOkHttpClient: Lazy<OkHttpClient>, - retrofitFactory: RetrofitFactory): TermsAPI { + fun providesTermsAPI( + @UnauthenticatedWithCertificate unauthenticatedOkHttpClient: Lazy<OkHttpClient>, + retrofitFactory: RetrofitFactory + ): TermsAPI { val retrofit = retrofitFactory.create(unauthenticatedOkHttpClient, "https://foo.bar") return retrofit.create(TermsAPI::class.java) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/DefaultThirdPartyService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/DefaultThirdPartyService.kt index 210cb192e7f7c3c832432041d87982c025548a93..c8b9eaf81065a8a073d66a6dcc86417e473f470f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/DefaultThirdPartyService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/DefaultThirdPartyService.kt @@ -21,8 +21,10 @@ import org.matrix.android.sdk.api.session.thirdparty.ThirdPartyService import org.matrix.android.sdk.api.session.thirdparty.model.ThirdPartyUser import javax.inject.Inject -internal class DefaultThirdPartyService @Inject constructor(private val getThirdPartyProtocolTask: GetThirdPartyProtocolsTask, - private val getThirdPartyUserTask: GetThirdPartyUserTask) : +internal class DefaultThirdPartyService @Inject constructor( + private val getThirdPartyProtocolTask: GetThirdPartyProtocolsTask, + private val getThirdPartyUserTask: GetThirdPartyUserTask +) : ThirdPartyService { override suspend fun getThirdPartyProtocols(): Map<String, ThirdPartyProtocol> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/ThirdPartyAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/ThirdPartyAPI.kt index 3ecc39ac9484d0f371896b3f069e75292b7f64a7..6759205bf345babfeaecea4ed4056aac29fb26e9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/ThirdPartyAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/thirdparty/ThirdPartyAPI.kt @@ -39,6 +39,8 @@ internal interface ThirdPartyAPI { * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-thirdparty-user-protocol */ @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "thirdparty/user/{protocol}") - suspend fun getThirdPartyUser(@Path("protocol") protocol: String, - @QueryMap params: Map<String, String>?): List<ThirdPartyUser> + suspend fun getThirdPartyUser( + @Path("protocol") protocol: String, + @QueryMap params: Map<String, String>? + ): List<ThirdPartyUser> } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt index 4ffc42e714ed1afa75d88832957f043c3090be5f..660cf118dff276cff2e71a04293b0c48d3343ed3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/DefaultUserService.kt @@ -26,10 +26,12 @@ import org.matrix.android.sdk.internal.session.user.accountdata.UpdateIgnoredUse import org.matrix.android.sdk.internal.session.user.model.SearchUserTask import javax.inject.Inject -internal class DefaultUserService @Inject constructor(private val userDataSource: UserDataSource, - private val searchUserTask: SearchUserTask, - private val updateIgnoredUserIdsTask: UpdateIgnoredUserIdsTask, - private val getProfileInfoTask: GetProfileInfoTask) : UserService { +internal class DefaultUserService @Inject constructor( + private val userDataSource: UserDataSource, + private val searchUserTask: SearchUserTask, + private val updateIgnoredUserIdsTask: UpdateIgnoredUserIdsTask, + private val getProfileInfoTask: GetProfileInfoTask +) : UserService { override fun getUser(userId: String): User? { return userDataSource.getUser(userId) @@ -59,9 +61,11 @@ internal class DefaultUserService @Inject constructor(private val userDataSource return userDataSource.getIgnoredUsersLive() } - override suspend fun searchUsersDirectory(search: String, - limit: Int, - excludedUserIds: Set<String>): List<User> { + override suspend fun searchUsersDirectory( + search: String, + limit: Int, + excludedUserIds: Set<String> + ): List<User> { val params = SearchUserTask.Params(limit, search, excludedUserIds) return searchUserTask.execute(params) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt index e83725b10da19b651ad59073fc9c46f4763c0ef7..f9feb04e97ae868fe4600cfd3e59311fcd786b28 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/UserDataSource.kt @@ -36,8 +36,10 @@ import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase import javax.inject.Inject -internal class UserDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy, - private val realmSessionProvider: RealmSessionProvider) { +internal class UserDataSource @Inject constructor( + @SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider +) { private val realmDataSourceFactory: Monarchy.RealmDataSourceFactory<UserEntity> by lazy { monarchy.createDataSourceFactory { realm -> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataAPI.kt index bbeff18c01302a49f67f77748673f56492c69f3e..b283d518458eb674fbe720bebbe57db1ac24f225 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/AccountDataAPI.kt @@ -27,11 +27,13 @@ internal interface AccountDataAPI { * Set some account_data for the client. * * @param userId the user id - * @param type the type + * @param type the type * @param params the put params */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/account_data/{type}") - suspend fun setAccountData(@Path("userId") userId: String, - @Path("type") type: String, - @Body params: Any) + suspend fun setAccountData( + @Path("userId") userId: String, + @Path("type") type: String, + @Body params: Any + ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateUserAccountDataTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateUserAccountDataTask.kt index 88db381852ffcf66e09221db6180dbcef964fde2..ff0e960f0fdc4b07958e08b887b70f1c16e3b345 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateUserAccountDataTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UpdateUserAccountDataTask.kt @@ -35,8 +35,9 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa fun getData(): Any } - data class IdentityParams(override val type: String = UserAccountDataTypes.TYPE_IDENTITY_SERVER, - private val identityContent: IdentityServerContent + data class IdentityParams( + override val type: String = UserAccountDataTypes.TYPE_IDENTITY_SERVER, + private val identityContent: IdentityServerContent ) : Params { override fun getData(): Any { @@ -44,8 +45,9 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa } } - data class AcceptedTermsParams(override val type: String = UserAccountDataTypes.TYPE_ACCEPTED_TERMS, - private val acceptedTermsContent: AcceptedTermsContent + data class AcceptedTermsParams( + override val type: String = UserAccountDataTypes.TYPE_ACCEPTED_TERMS, + private val acceptedTermsContent: AcceptedTermsContent ) : Params { override fun getData(): Any { @@ -54,8 +56,9 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa } // TODO Use [UserAccountDataDirectMessages] class? - data class DirectChatParams(override val type: String = UserAccountDataTypes.TYPE_DIRECT_MESSAGES, - private val directMessages: Map<String, List<String>> + data class DirectChatParams( + override val type: String = UserAccountDataTypes.TYPE_DIRECT_MESSAGES, + private val directMessages: Map<String, List<String>> ) : Params { override fun getData(): Any { @@ -63,8 +66,9 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa } } - data class BreadcrumbsParams(override val type: String = UserAccountDataTypes.TYPE_BREADCRUMBS, - private val breadcrumbsContent: BreadcrumbsContent + data class BreadcrumbsParams( + override val type: String = UserAccountDataTypes.TYPE_BREADCRUMBS, + private val breadcrumbsContent: BreadcrumbsContent ) : Params { override fun getData(): Any { @@ -72,24 +76,29 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa } } - data class AllowedWidgets(override val type: String = UserAccountDataTypes.TYPE_ALLOWED_WIDGETS, - private val allowedWidgetsContent: AllowedWidgetsContent) : Params { + data class AllowedWidgets( + override val type: String = UserAccountDataTypes.TYPE_ALLOWED_WIDGETS, + private val allowedWidgetsContent: AllowedWidgetsContent + ) : Params { override fun getData(): Any { return allowedWidgetsContent } } - data class IntegrationProvisioning(override val type: String = UserAccountDataTypes.TYPE_INTEGRATION_PROVISIONING, - private val integrationProvisioningContent: IntegrationProvisioningContent) : Params { + data class IntegrationProvisioning( + override val type: String = UserAccountDataTypes.TYPE_INTEGRATION_PROVISIONING, + private val integrationProvisioningContent: IntegrationProvisioningContent + ) : Params { override fun getData(): Any { return integrationProvisioningContent } } - data class AnyParams(override val type: String, - private val any: Any + data class AnyParams( + override val type: String, + private val any: Any ) : Params { override fun getData(): Any { return any diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UserAccountDataDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UserAccountDataDataSource.kt index 2c3d660333ec9dba8d0ed4bb9726a64580a3ade7..39f155096ac37ea458a6dd8724977ea08906f87d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UserAccountDataDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/user/accountdata/UserAccountDataDataSource.kt @@ -31,9 +31,11 @@ import org.matrix.android.sdk.internal.database.model.UserAccountDataEntityField import org.matrix.android.sdk.internal.di.SessionDatabase import javax.inject.Inject -internal class UserAccountDataDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy, - private val realmSessionProvider: RealmSessionProvider, - private val accountDataMapper: AccountDataMapper) { +internal class UserAccountDataDataSource @Inject constructor( + @SessionDatabase private val monarchy: Monarchy, + private val realmSessionProvider: RealmSessionProvider, + private val accountDataMapper: AccountDataMapper +) { fun getAccountDataEvent(type: String): UserAccountDataEvent? { return getAccountDataEvents(setOf(type)).firstOrNull() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt index 06508def1c4e2787e75874803d70d8da26951e65..51e6812a8bd532377a1f302ae923c5dd0d194625 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/CreateWidgetTask.kt @@ -41,10 +41,12 @@ internal interface CreateWidgetTask : Task<CreateWidgetTask.Params, String> { ) } -internal class DefaultCreateWidgetTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy, - private val roomAPI: RoomAPI, - @UserId private val userId: String, - private val globalErrorReceiver: GlobalErrorReceiver) : CreateWidgetTask { +internal class DefaultCreateWidgetTask @Inject constructor( + @SessionDatabase private val monarchy: Monarchy, + private val roomAPI: RoomAPI, + @UserId private val userId: String, + private val globalErrorReceiver: GlobalErrorReceiver +) : CreateWidgetTask { override suspend fun execute(params: CreateWidgetTask.Params): String { val response = executeRequest(globalErrorReceiver) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetPostAPIMediator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetPostAPIMediator.kt index 1da682791618ff56e64b84ec3aafe41878202306..2665809d9a7eb277a7a04eab00efc4c735c53b23 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetPostAPIMediator.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetPostAPIMediator.kt @@ -27,8 +27,10 @@ import timber.log.Timber import java.lang.reflect.Type import javax.inject.Inject -internal class DefaultWidgetPostAPIMediator @Inject constructor(private val moshi: Moshi, - private val widgetPostMessageAPIProvider: WidgetPostMessageAPIProvider) : +internal class DefaultWidgetPostAPIMediator @Inject constructor( + private val moshi: Moshi, + private val widgetPostMessageAPIProvider: WidgetPostMessageAPIProvider +) : WidgetPostAPIMediator { private val jsonAdapter = moshi.adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE) @@ -95,7 +97,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh /** * Send a boolean response. * - * @param response the response + * @param response the response * @param eventData the modular data */ override fun sendBoolResponse(response: Boolean, eventData: JsonDict) { @@ -106,7 +108,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh /** * Send an integer response. * - * @param response the response + * @param response the response * @param eventData the modular data */ override fun sendIntegerResponse(response: Int, eventData: JsonDict) { @@ -116,7 +118,9 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh /** * Send an object response. * - * @param response the response + * @param T the Json type + * @param type the type + * @param response the response * @param eventData the modular data */ override fun <T> sendObjectResponse(type: Type, response: T?, eventData: JsonDict) { @@ -145,7 +149,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh /** * Send an error. * - * @param message the error message + * @param message the error message * @param eventData the modular data */ override fun sendError(message: String, eventData: JsonDict) { @@ -162,7 +166,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh /** * Send the response to the javascript. * - * @param jsString the response data + * @param jsString the response data * @param eventData the modular data */ private fun sendResponse(jsString: String, eventData: JsonDict) = uiHandler.post { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetService.kt index 53a435d2172c127b22120322974c4b55d66f0fce..7b2edf2dbf3f22b189a5018e07ee1015c36a377d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetService.kt @@ -26,9 +26,11 @@ import org.matrix.android.sdk.api.session.widgets.model.Widget import javax.inject.Inject import javax.inject.Provider -internal class DefaultWidgetService @Inject constructor(private val widgetManager: WidgetManager, - private val widgetURLFormatter: WidgetURLFormatter, - private val widgetPostAPIMediator: Provider<WidgetPostAPIMediator>) : +internal class DefaultWidgetService @Inject constructor( + private val widgetManager: WidgetManager, + private val widgetURLFormatter: WidgetURLFormatter, + private val widgetPostAPIMediator: Provider<WidgetPostAPIMediator> +) : WidgetService { override fun getWidgetURLFormatter(): WidgetURLFormatter { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetURLFormatter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetURLFormatter.kt index 5879b6244676e362829089ec47318a636969ee00..019edf21b663cc4bfcea4d57f933511eb9421b92 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetURLFormatter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/DefaultWidgetURLFormatter.kt @@ -30,9 +30,10 @@ import org.matrix.android.sdk.internal.session.widgets.token.GetScalarTokenTask import javax.inject.Inject @SessionScope -internal class DefaultWidgetURLFormatter @Inject constructor(private val integrationManager: IntegrationManager, - private val getScalarTokenTask: GetScalarTokenTask, - private val matrixConfiguration: MatrixConfiguration +internal class DefaultWidgetURLFormatter @Inject constructor( + private val integrationManager: IntegrationManager, + private val getScalarTokenTask: GetScalarTokenTask, + private val matrixConfiguration: MatrixConfiguration ) : IntegrationManagerService.Listener, WidgetURLFormatter, SessionLifecycleObserver { private lateinit var currentConfig: IntegrationManagerConfig diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt index 07ed91c1790ff82ac64864a968794ff3981f498f..3f7db93b97d23efe45721238f63c3b03c641a8d7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetManager.kt @@ -45,12 +45,14 @@ import org.matrix.android.sdk.internal.session.widgets.helper.extractWidgetSeque import javax.inject.Inject @SessionScope -internal class WidgetManager @Inject constructor(private val integrationManager: IntegrationManager, - private val userAccountDataDataSource: UserAccountDataDataSource, - private val stateEventDataSource: StateEventDataSource, - private val createWidgetTask: CreateWidgetTask, - private val widgetFactory: WidgetFactory, - @UserId private val userId: String) : +internal class WidgetManager @Inject constructor( + private val integrationManager: IntegrationManager, + private val userAccountDataDataSource: UserAccountDataDataSource, + private val stateEventDataSource: StateEventDataSource, + private val createWidgetTask: CreateWidgetTask, + private val widgetFactory: WidgetFactory, + @UserId private val userId: String +) : IntegrationManagerService.Listener, SessionLifecycleObserver { @@ -103,8 +105,10 @@ internal class WidgetManager @Inject constructor(private val integrationManager: return widgetFactory.computeURL(widget, isLightTheme) } - private fun List<Event>.mapEventsToWidgets(widgetTypes: Set<String>? = null, - excludedTypes: Set<String>? = null): List<Widget> { + private fun List<Event>.mapEventsToWidgets( + widgetTypes: Set<String>? = null, + excludedTypes: Set<String>? = null + ): List<Widget> { val widgetEvents = this // Widget id -> widget val widgets: MutableMap<String, Widget> = HashMap() @@ -149,8 +153,10 @@ internal class WidgetManager @Inject constructor(private val integrationManager: return widgetsAccountData.mapToWidgets(widgetTypes, excludedTypes) } - private fun UserAccountDataEvent.mapToWidgets(widgetTypes: Set<String>? = null, - excludedTypes: Set<String>? = null): List<Widget> { + private fun UserAccountDataEvent.mapToWidgets( + widgetTypes: Set<String>? = null, + excludedTypes: Set<String>? = null + ): List<Widget> { return extractWidgetSequence(widgetFactory) .filter { val widgetType = it.widgetContent.type ?: return@filter false diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPI.kt index b871a317c88c5217afda2c97f385e2918b943d15..2a4af9ffaaccef88372a5c76ecd20edd269d001d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPI.kt @@ -27,12 +27,17 @@ internal interface WidgetsAPI { * Register to the server. * * @param body the body content (Ref: https://github.com/matrix-org/matrix-doc/pull/1961) + * @param version the widget API version */ @POST("register") - suspend fun register(@Body body: OpenIdToken, - @Query("v") version: String?): RegisterWidgetResponse + suspend fun register( + @Body body: OpenIdToken, + @Query("v") version: String? + ): RegisterWidgetResponse @GET("account") - suspend fun validateToken(@Query("scalar_token") scalarToken: String?, - @Query("v") version: String?) + suspend fun validateToken( + @Query("scalar_token") scalarToken: String?, + @Query("v") version: String? + ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPIProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPIProvider.kt index 48c8fcdb03340d49e2508b874be8fdfcc864d891..25caadbade9d96dfd870ba600fbac9bf0485e409 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPIProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/WidgetsAPIProvider.kt @@ -24,8 +24,10 @@ import org.matrix.android.sdk.internal.session.SessionScope import javax.inject.Inject @SessionScope -internal class WidgetsAPIProvider @Inject constructor(@Unauthenticated private val okHttpClient: Lazy<OkHttpClient>, - private val retrofitFactory: RetrofitFactory) { +internal class WidgetsAPIProvider @Inject constructor( + @Unauthenticated private val okHttpClient: Lazy<OkHttpClient>, + private val retrofitFactory: RetrofitFactory +) { // Map to keep one WidgetAPI instance by serverUrl private val widgetsAPIs = mutableMapOf<String, WidgetsAPI>() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt index a5e74a8af0fe400fdd25a96ec14394ca616b2ff6..8bd61a7bdf5ffdb962bd7acb56e353e6861ef4e3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/helper/WidgetFactory.kt @@ -33,11 +33,13 @@ import org.matrix.android.sdk.internal.session.user.UserDataSource import java.net.URLEncoder import javax.inject.Inject -internal class WidgetFactory @Inject constructor(private val userDataSource: UserDataSource, - private val realmSessionProvider: RealmSessionProvider, - private val displayNameResolver: DisplayNameResolver, - private val urlResolver: ContentUrlResolver, - @UserId private val userId: String) { +internal class WidgetFactory @Inject constructor( + private val userDataSource: UserDataSource, + private val realmSessionProvider: RealmSessionProvider, + private val displayNameResolver: DisplayNameResolver, + private val urlResolver: ContentUrlResolver, + @UserId private val userId: String +) { fun create(widgetEvent: Event): Widget? { val widgetContent = widgetEvent.content.toModel<WidgetContent>() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/token/GetScalarTokenTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/token/GetScalarTokenTask.kt index 17797cad52d4c29213b0e6c7adc8c87429f7af49..49ae52afaaed17155ac8c1bcfe3efcd2fab657fe 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/token/GetScalarTokenTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/widgets/token/GetScalarTokenTask.kt @@ -37,9 +37,11 @@ internal interface GetScalarTokenTask : Task<GetScalarTokenTask.Params, String> private const val WIDGET_API_VERSION = "1.1" -internal class DefaultGetScalarTokenTask @Inject constructor(private val widgetsAPIProvider: WidgetsAPIProvider, - private val scalarTokenStore: ScalarTokenStore, - private val getOpenIdTokenTask: GetOpenIdTokenTask) : GetScalarTokenTask { +internal class DefaultGetScalarTokenTask @Inject constructor( + private val widgetsAPIProvider: WidgetsAPIProvider, + private val scalarTokenStore: ScalarTokenStore, + private val getOpenIdTokenTask: GetOpenIdTokenTask +) : GetScalarTokenTask { override suspend fun execute(params: GetScalarTokenTask.Params): String { val widgetsAPI = widgetsAPIProvider.get(params.serverUrl) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/ConfigurableTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/ConfigurableTask.kt index bc80cf7ee8bd3fd7af38f5f6d07b16a098f264ef..eead25b57c008eb3d953e3e019886c1bf526e931 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/ConfigurableTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/ConfigurableTask.kt @@ -21,8 +21,9 @@ import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.util.Cancelable import java.util.UUID -internal fun <PARAMS, RESULT> Task<PARAMS, RESULT>.configureWith(params: PARAMS, - init: (ConfigurableTask.Builder<PARAMS, RESULT>.() -> Unit) = {} +internal fun <PARAMS, RESULT> Task<PARAMS, RESULT>.configureWith( + params: PARAMS, + init: (ConfigurableTask.Builder<PARAMS, RESULT>.() -> Unit) = {} ): ConfigurableTask<PARAMS, RESULT> { return ConfigurableTask.Builder(this, params).apply(init).build() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/CoroutineSequencer.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/CoroutineSequencer.kt index 80081e318618d790d1687515973cd3f5b6d8030d..dd4c5e762343ddda325a701078b1cf1caaea0c97 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/CoroutineSequencer.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/CoroutineSequencer.kt @@ -24,6 +24,7 @@ import kotlinx.coroutines.sync.withPermit */ internal interface CoroutineSequencer { /** + * @param T generic type * @param block the suspendable block to execute * @return the result of the block */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/TaskExecutor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/TaskExecutor.kt index 57574a96fa9f120d705b421c6176d5a50c8cf343..5e685bd546d826caccf7650f5335d8c8e7f2ef53 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/TaskExecutor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/TaskExecutor.kt @@ -57,11 +57,11 @@ internal class TaskExecutor @Inject constructor(private val coroutineDispatchers fun cancelAll() = executorScope.coroutineContext.cancelChildren() private fun TaskThread.toDispatcher() = when (this) { - TaskThread.MAIN -> coroutineDispatchers.main + TaskThread.MAIN -> coroutineDispatchers.main TaskThread.COMPUTATION -> coroutineDispatchers.computation - TaskThread.IO -> coroutineDispatchers.io - TaskThread.CALLER -> EmptyCoroutineContext - TaskThread.CRYPTO -> coroutineDispatchers.crypto - TaskThread.DM_VERIF -> coroutineDispatchers.dmVerif + TaskThread.IO -> coroutineDispatchers.io + TaskThread.CALLER -> EmptyCoroutineContext + TaskThread.CRYPTO -> coroutineDispatchers.crypto + TaskThread.DM_VERIF -> coroutineDispatchers.dmVerif } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CancelableWork.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CancelableWork.kt index 6b04cea936a8b96450c900eea370fde3580565fd..2240a408efc87a90d76878df08b07f3daa9cbcd2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CancelableWork.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CancelableWork.kt @@ -20,8 +20,10 @@ import androidx.work.WorkManager import org.matrix.android.sdk.api.util.Cancelable import java.util.UUID -internal class CancelableWork(private val workManager: WorkManager, - private val workId: UUID) : Cancelable { +internal class CancelableWork( + private val workManager: WorkManager, + private val workId: UUID +) : Cancelable { override fun cancel() { workManager.cancelWorkById(workId) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Glob.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Glob.kt index 60f9609586858e061bcddc847ad04dae3477e49e..a4aae803480cf546a41c0e4320d7613372bb9861 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Glob.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Glob.kt @@ -27,9 +27,9 @@ internal fun String.simpleGlobToRegExp(): String { // append("^") string.forEach { char -> when (char) { - '*' -> append(".*") - '?' -> append(".") - '.' -> append("\\.") + '*' -> append(".*") + '?' -> append(".") + '.' -> append("\\.") '\\' -> append("\\\\") else -> append(char) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/JsonCanonicalizer.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/JsonCanonicalizer.kt index 94aa238789fd9dbc8e28bb598a66e2fa744ab3c0..6e6007f491a8e089260f701d8cface64f62236c7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/JsonCanonicalizer.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/JsonCanonicalizer.kt @@ -53,12 +53,12 @@ internal object JsonCanonicalizer { /** * Canonicalize a JSON element. * - * @param src the src + * @param any the src * @return the canonicalize element */ private fun canonicalizeRecursive(any: Any): String { when (any) { - is JSONArray -> { + is JSONArray -> { // Canonicalize each element of the array return (0 until any.length()).joinToString(separator = ",", prefix = "[", postfix = "]") { canonicalizeRecursive(any.get(it)) @@ -88,8 +88,8 @@ internal object JsonCanonicalizer { append("}") } } - is String -> return JSONObject.quote(any) - else -> return any.toString() + is String -> return JSONObject.quote(any) + else -> return any.toString() } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/LogUtil.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/LogUtil.kt index ffad0b856c368d750256bfb254ae2643fa977e9f..2306ddf850b633c3895d5769237af3ae90e4d10a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/LogUtil.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/LogUtil.kt @@ -33,10 +33,12 @@ internal fun <T> Collection<T>.logLimit(maxQuantity: Int = 5): String { } } -internal suspend fun <T> logDuration(message: String, - loggerTag: LoggerTag, - clock: Clock, - block: suspend () -> T): T { +internal suspend fun <T> logDuration( + message: String, + loggerTag: LoggerTag, + clock: Clock, + block: suspend () -> T +): T { Timber.tag(loggerTag.value).d("$message -- BEGIN") val start = clock.epochMillis() val result = logRamUsage(message) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt index d9fd312a6fc1d4a9d2635eff929a219cd88c6a75..c6a417f6eb6ee564ab396ccf308504df02f061f9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt @@ -54,7 +54,7 @@ internal fun convertFromUTF8(s: String): String { /** * Returns whether a string contains an occurrence of another, as a standalone word, regardless of case. * - * @param subString the string to search for + * @param subString the string to search for * @return whether a match was found */ internal fun String.caseInsensitiveFind(subString: String): Boolean { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/UrlUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/UrlUtils.kt index fbbec1a100985df2227a000d373104c27bae3f35..cbaec586d0542a31c2436397c5650f655b944377 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/UrlUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/UrlUtils.kt @@ -32,9 +32,9 @@ internal fun String.isValidUrl(): Boolean { */ internal fun String.ensureProtocol(): String { return when { - isEmpty() -> this + isEmpty() -> this !startsWith("http") -> "https://$this" - else -> this + else -> this } } @@ -43,8 +43,8 @@ internal fun String.ensureProtocol(): String { */ internal fun String.ensureTrailingSlash(): String { return when { - isEmpty() -> this + isEmpty() -> this !endsWith("/") -> "$this/" - else -> this + else -> this } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/database/RealmMigrator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/database/RealmMigrator.kt index 8f3c89f2d4282f9c058c9ab7654e5ccd1e8f429a..8da1bed97e0c5385e9aae4133fb278c16b078816 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/database/RealmMigrator.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/database/RealmMigrator.kt @@ -20,8 +20,10 @@ import io.realm.DynamicRealm import io.realm.RealmObjectSchema import timber.log.Timber -internal abstract class RealmMigrator(private val realm: DynamicRealm, - private val targetSchemaVersion: Int) { +internal abstract class RealmMigrator( + private val realm: DynamicRealm, + private val targetSchemaVersion: Int +) { fun perform() { Timber.d("Migrate ${realm.configuration.realmFileName} to $targetSchemaVersion") doMigrate(realm) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt index 0d4a5ac28f25400a56b3c1a39ef498cca8cb6c98..003bdab9cbd793f11d105266bf0550a187ce3bb4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt @@ -75,7 +75,8 @@ internal class DefaultGetWellknownTask @Inject constructor( * - validate homeserver url and identity server url if provide in .well-known result * - return action and .well-known data * - * @param domain: homeserver domain, deduced from mx userId (ex: "matrix.org" from userId "@user:matrix.org") + * @param domain homeserver domain, deduced from mx userId (ex: "matrix.org" from userId "@user:matrix.org") + * @param client Http client to perform the request */ private suspend fun findClientConfig(domain: String, client: OkHttpClient): WellknownResult { val wellKnownAPI = retrofitFactory.create(client, "https://dummy.org") @@ -100,25 +101,25 @@ internal class DefaultGetWellknownTask @Inject constructor( } } catch (throwable: Throwable) { when (throwable) { - is UnrecognizedCertificateException -> { + is UnrecognizedCertificateException -> { throw Failure.UnrecognizedCertificateFailure( "https://$domain", throwable.fingerprint ) } - is Failure.NetworkConnection -> { + is Failure.NetworkConnection -> { WellknownResult.Ignore } - is Failure.OtherServerError -> { + is Failure.OtherServerError -> { when (throwable.httpCode) { HttpsURLConnection.HTTP_NOT_FOUND -> WellknownResult.Ignore - else -> WellknownResult.FailPrompt(null, null) + else -> WellknownResult.FailPrompt(null, null) } } is MalformedJsonException, is EOFException -> { WellknownResult.FailPrompt(null, null) } - else -> { + else -> { throw throwable } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt index 95b3662c670c6973e2132ba1cc50f378c196a449..52146ef484b81746b89c66be779d260bbd1e1ef7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt @@ -27,6 +27,7 @@ import org.matrix.android.sdk.internal.di.MatrixScope import org.matrix.android.sdk.internal.session.content.UploadContentWorker import org.matrix.android.sdk.internal.session.group.GetGroupDataWorker import org.matrix.android.sdk.internal.session.pushers.AddPusherWorker +import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.DeactivateLiveLocationShareWorker import org.matrix.android.sdk.internal.session.room.send.MultipleEventSendingDispatcherWorker import org.matrix.android.sdk.internal.session.room.send.RedactEventWorker import org.matrix.android.sdk.internal.session.room.send.SendEventWorker @@ -48,25 +49,27 @@ internal class MatrixWorkerFactory @Inject constructor(private val sessionManage ): ListenableWorker? { Timber.d("MatrixWorkerFactory.createWorker for $workerClassName") return when (workerClassName) { - CheckFactoryWorker::class.java.name -> + CheckFactoryWorker::class.java.name -> CheckFactoryWorker(appContext, workerParameters, true) - AddPusherWorker::class.java.name -> + AddPusherWorker::class.java.name -> AddPusherWorker(appContext, workerParameters, sessionManager) - GetGroupDataWorker::class.java.name -> + GetGroupDataWorker::class.java.name -> GetGroupDataWorker(appContext, workerParameters, sessionManager) MultipleEventSendingDispatcherWorker::class.java.name -> MultipleEventSendingDispatcherWorker(appContext, workerParameters, sessionManager) - RedactEventWorker::class.java.name -> + RedactEventWorker::class.java.name -> RedactEventWorker(appContext, workerParameters, sessionManager) - SendEventWorker::class.java.name -> + SendEventWorker::class.java.name -> SendEventWorker(appContext, workerParameters, sessionManager) - SyncWorker::class.java.name -> + SyncWorker::class.java.name -> SyncWorker(appContext, workerParameters, sessionManager) - UpdateTrustWorker::class.java.name -> + UpdateTrustWorker::class.java.name -> UpdateTrustWorker(appContext, workerParameters, sessionManager) - UploadContentWorker::class.java.name -> + UploadContentWorker::class.java.name -> UploadContentWorker(appContext, workerParameters, sessionManager) - else -> { + DeactivateLiveLocationShareWorker::class.java.name -> + DeactivateLiveLocationShareWorker(appContext, workerParameters, sessionManager) + else -> { Timber.w("No worker defined on MatrixWorkerFactory for $workerClassName will delegate to default.") // Return null to delegate to the default WorkerFactory. null @@ -78,9 +81,11 @@ internal class MatrixWorkerFactory @Inject constructor(private val sessionManage * This worker is launched by the factory with the isCreatedByMatrixWorkerFactory flag to true. * If the MatrixWorkerFactory is not set up, it will default to the other constructor and it will throw */ - class CheckFactoryWorker(context: Context, - workerParameters: WorkerParameters, - private val isCreatedByMatrixWorkerFactory: Boolean) : + class CheckFactoryWorker( + context: Context, + workerParameters: WorkerParameters, + private val isCreatedByMatrixWorkerFactory: Boolean + ) : CoroutineWorker(context, workerParameters) { // Called by WorkManager if there is no MatrixWorkerFactory diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us000InitMatrix.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us000InitMatrix.kt new file mode 100644 index 0000000000000000000000000000000000000000..06c6cc9ef9d9eb073aaee0140ae6d7a92f781cff --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us000InitMatrix.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("unused") + +package org.matrix.android.sdk.userstories + +/** + * ### Title + * Init a Matrix object. + * + * ### Required APIs: + * - [org.matrix.android.sdk.api.Matrix] constructor + */ +class Us000InitMatrix private constructor() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us100SignIn.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us100SignIn.kt new file mode 100644 index 0000000000000000000000000000000000000000..f508a75db7476f630eefd6dc88393b87816de6aa --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us100SignIn.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("unused") + +package org.matrix.android.sdk.userstories + +/** + * ### Title + * Sign in to an existing account. + * + * #### Required APIs: + * - [org.matrix.android.sdk.api.Matrix.authenticationService] + * - [org.matrix.android.sdk.api.auth.AuthenticationService.getLoginFlow] + * - [org.matrix.android.sdk.api.auth.AuthenticationService.getLoginWizard] + * - [org.matrix.android.sdk.api.auth.login.LoginWizard.login] + */ +class Us100SignIn private constructor() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us150VerifySession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us150VerifySession.kt new file mode 100644 index 0000000000000000000000000000000000000000..ac56cc35dd9afa57f7c1274f6385efcb11a24bb1 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us150VerifySession.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("unused") + +package org.matrix.android.sdk.userstories + +/** + * ### Title + * Verify a Session after a Sign in. + * + * #### Required APIs: + * - TODO + */ +class Us150VerifySession private constructor() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us190SignOut.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us190SignOut.kt new file mode 100644 index 0000000000000000000000000000000000000000..0c74c0dfef0e2b60703417dc6b21a0cf784489ee --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us190SignOut.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("unused") + +package org.matrix.android.sdk.userstories + +/** + * ### Title + * Sign out. + * + * #### Required APIs: + * - TODO + */ +class Us190SignOut private constructor() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us200RoomList.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us200RoomList.kt new file mode 100644 index 0000000000000000000000000000000000000000..1f0b2e41038d6858196866fdb9c5976a1dd17f3f --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us200RoomList.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("unused") + +package org.matrix.android.sdk.userstories + +/** + * ### Title + * Get the Room list. + * + * #### Required APIs: + * - TODO + */ +class Us200RoomList private constructor() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us300RoomTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us300RoomTimeline.kt new file mode 100644 index 0000000000000000000000000000000000000000..5db06f95f6a74fd3410f3ca5feb4043440cb82b6 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us300RoomTimeline.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("unused") + +package org.matrix.android.sdk.userstories + +/** + * ### Title + * Display a Room timeline, and navigate backward and forward. + * + * #### Required APIs: + * - TODO + */ +class Us300RoomTimeline private constructor() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us350RoomTimelineFromPermalink.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us350RoomTimelineFromPermalink.kt new file mode 100644 index 0000000000000000000000000000000000000000..5e0f6d3b3d9c4fcd0d37b6b51e6fd39132e4ee19 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us350RoomTimelineFromPermalink.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("unused") + +package org.matrix.android.sdk.userstories + +/** + * ### Title + * Display a Room timeline at a specific point. + * + * #### Required APIs: + * - TODO + */ +class Us350RoomTimelineFromPermalink private constructor() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us400RoomSendContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us400RoomSendContent.kt new file mode 100644 index 0000000000000000000000000000000000000000..3f72cd0b9e9f89d270cffd8a5d655e41aab286c1 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us400RoomSendContent.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("unused") + +package org.matrix.android.sdk.userstories + +/** + * ### Title + * Send content to a room, including monitoring the sending state. + * + * #### Required APIs: + * - TODO + */ +class Us400RoomSendContent private constructor() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us500Notification.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us500Notification.kt new file mode 100644 index 0000000000000000000000000000000000000000..c5c2107fa620319bf18980074b05da843138dfa8 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us500Notification.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("unused") + +package org.matrix.android.sdk.userstories + +/** + * ### Title + * Get notified when new Events are received. + * + * #### Required APIs: + * - TODO + */ +class Us500Notification private constructor() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us600SyncWithTheServer.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us600SyncWithTheServer.kt new file mode 100644 index 0000000000000000000000000000000000000000..6b8fb87df7320767e5fdf14521fca4586f2dbf16 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/userstories/Us600SyncWithTheServer.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("unused") + +package org.matrix.android.sdk.userstories + +/** + * ### Title + * Manage the sync with the server. + * + * #### Required APIs: + * - TODO + */ +class Us600SyncWithTheServer private constructor() diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersionTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersionTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..413af9c434f7bbd6c5baf9a72dd053d66f29ef9f --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/auth/version/HomeServerVersionTest.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.matrix.android.sdk.internal.auth.version + +import org.amshove.kluent.internal.assertEquals +import org.junit.Test + +class HomeServerVersionTest { + + @Test + fun `given a semantic version, when parsing, then converts to home server version`() { + val supportedVersions = listOf( + case("1.5", expected = aVersion(1, 5, 0)), + case("0.5.1", expected = aVersion(0, 5, 1)), + case("1.0.0", expected = aVersion(1, 0, 0)), + case("1.10.3", expected = aVersion(1, 10, 3)), + ).withPrefixes("v", "r") + + val unsupportedVersions = listOf( + case("v-1.5.1", expected = null), + case("1.4.", expected = null), + case("1.5.1.", expected = null), + case("r1", expected = null), + case("a", expected = null), + case("1a.2b.3c", expected = null), + case("r", expected = null), + ) + + (supportedVersions + unsupportedVersions).forEach { (input, expected) -> + val result = HomeServerVersion.parse(input) + + assertEquals(expected, result, "Expected $input to be $expected but got $result") + } + } +} + +private fun aVersion(major: Int, minor: Int, patch: Int) = HomeServerVersion(major, minor, patch) +private fun case(input: String, expected: HomeServerVersion?) = Case(input, expected) + +private fun List<Case>.withPrefixes(vararg prefixes: String) = map { case -> + prefixes.map { prefix -> case.copy(input = "$prefix${case.input}") } +}.flatten() + +private data class Case(val input: String, val expected: HomeServerVersion?) diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapperTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapperTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..47d5f465256be23cbc4edc5ff07be4743423ea75 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/database/mapper/LiveLocationShareAggregatedSummaryMapperTest.kt @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.database.mapper + +import com.squareup.moshi.Moshi +import org.amshove.kluent.shouldBeEqualTo +import org.junit.Test +import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary +import org.matrix.android.sdk.api.session.room.model.message.LocationInfo +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent +import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity + +private const val ANY_USER_ID = "a-user-id" +private const val ANY_ACTIVE_STATE = true +private const val ANY_TIMEOUT = 123L +private val A_LOCATION_INFO = LocationInfo("a-geo-uri") + +class LiveLocationShareAggregatedSummaryMapperTest { + + private val mapper = LiveLocationShareAggregatedSummaryMapper() + + @Test + fun `given an entity then result should be mapped correctly`() { + val entity = anEntity(content = MessageBeaconLocationDataContent(locationInfo = A_LOCATION_INFO)) + + val summary = mapper.map(entity) + + summary shouldBeEqualTo LiveLocationShareAggregatedSummary( + userId = ANY_USER_ID, + isActive = ANY_ACTIVE_STATE, + endOfLiveTimestampMillis = ANY_TIMEOUT, + lastLocationDataContent = MessageBeaconLocationDataContent(locationInfo = A_LOCATION_INFO) + ) + } + + private fun anEntity(content: MessageBeaconLocationDataContent) = LiveLocationShareAggregatedSummaryEntity( + userId = ANY_USER_ID, + isActive = ANY_ACTIVE_STATE, + endOfLiveTimestampMillis = ANY_TIMEOUT, + lastLocationContent = Moshi.Builder().build().adapter(MessageBeaconLocationDataContent::class.java).toJson(content) + ) +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollAggregationProcessorTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollAggregationProcessorTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..837bbeea268b60defcf9da04a6437c3b501db454 --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollAggregationProcessorTest.kt @@ -0,0 +1,162 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.aggregation.poll + +import io.mockk.every +import io.mockk.mockk +import io.realm.RealmList +import io.realm.RealmModel +import io.realm.RealmQuery +import org.amshove.kluent.shouldBeFalse +import org.amshove.kluent.shouldBeTrue +import org.junit.Before +import org.junit.Test +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.Room +import org.matrix.android.sdk.api.session.room.getTimelineEvent +import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper +import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity +import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntityFields +import org.matrix.android.sdk.internal.database.model.PollResponseAggregatedSummaryEntity +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.AN_EVENT_ID +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.AN_INVALID_POLL_RESPONSE_EVENT +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_BROKEN_POLL_REPLACE_EVENT +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_POLL_END_EVENT +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_POLL_REFERENCE_EVENT +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_POLL_REPLACE_EVENT +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_POLL_RESPONSE_EVENT +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_POLL_RESPONSE_EVENT_WITH_A_WRONG_REFERENCE +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_POLL_START_EVENT +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_ROOM_ID +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_TIMELINE_EVENT +import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollEventsTestData.A_USER_ID_1 +import org.matrix.android.sdk.test.fakes.FakeRealm + +class PollAggregationProcessorTest { + + private val pollAggregationProcessor: PollAggregationProcessor = DefaultPollAggregationProcessor() + private val realm = FakeRealm() + private val session = mockk<Session>() + + @Before + fun setup() { + mockEventAnnotationsSummaryEntity() + mockRoom(A_ROOM_ID, AN_EVENT_ID) + every { session.myUserId } returns A_USER_ID_1 + } + + @Test + fun `given a poll start event, when processing, then is ignored and returns false`() { + pollAggregationProcessor.handlePollStartEvent(realm.instance, A_POLL_START_EVENT).shouldBeFalse() + } + + @Test + fun `given a poll start event with a reference, when processing, then is ignored and returns false`() { + pollAggregationProcessor.handlePollStartEvent(realm.instance, A_POLL_REFERENCE_EVENT).shouldBeFalse() + } + + @Test + fun `given a poll start event with a replace relation but without a target event id, when processing, then is ignored and returns false`() { + pollAggregationProcessor.handlePollStartEvent(realm.instance, A_BROKEN_POLL_REPLACE_EVENT).shouldBeFalse() + } + + @Test + fun `given a poll start event with a replace, when processing, then is processed and returns true`() { + pollAggregationProcessor.handlePollStartEvent(realm.instance, A_POLL_REPLACE_EVENT).shouldBeTrue() + } + + @Test + fun `given a poll response event with a broken reference, when processing, then is ignored and returns false`() { + pollAggregationProcessor.handlePollResponseEvent(session, realm.instance, A_POLL_RESPONSE_EVENT_WITH_A_WRONG_REFERENCE).shouldBeFalse() + } + + @Test + fun `given a poll response event with a reference, when processing, then is processed and returns true`() { + every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity() + pollAggregationProcessor.handlePollResponseEvent(session, realm.instance, A_POLL_RESPONSE_EVENT).shouldBeTrue() + } + + @Test + fun `given a poll response event after poll is closed, when processing, then is ignored and returns false`() { + every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity().apply { + closedTime = (A_POLL_RESPONSE_EVENT.originServerTs ?: 0) - 1 + } + pollAggregationProcessor.handlePollResponseEvent(session, realm.instance, A_POLL_RESPONSE_EVENT).shouldBeFalse() + } + + @Test + fun `given a poll response event which is already processed, when processing, then is ignored and returns false`() { + every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity().apply { + sourceEvents = RealmList(A_POLL_RESPONSE_EVENT.eventId) + } + pollAggregationProcessor.handlePollResponseEvent(session, realm.instance, A_POLL_RESPONSE_EVENT).shouldBeFalse() + } + + @Test + fun `given a poll response event which is not one of the options, when processing, then is ignored and returns false`() { + every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity() + pollAggregationProcessor.handlePollResponseEvent(session, realm.instance, AN_INVALID_POLL_RESPONSE_EVENT).shouldBeFalse() + } + + @Test + fun `given a poll end event, when processing, then is processed and return true`() { + every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity() + val powerLevelsHelper = mockRedactionPowerLevels(A_USER_ID_1, true) + pollAggregationProcessor.handlePollEndEvent(session, powerLevelsHelper, realm.instance, A_POLL_END_EVENT).shouldBeTrue() + } + + @Test + fun `given a poll end event for my own poll without enough redaction power level, when processing, then is processed and returns true`() { + every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity() + val powerLevelsHelper = mockRedactionPowerLevels(A_USER_ID_1, false) + pollAggregationProcessor.handlePollEndEvent(session, powerLevelsHelper, realm.instance, A_POLL_END_EVENT).shouldBeTrue() + } + + @Test + fun `given a poll end event without enough redaction power level, when is processed, then is ignored and return false`() { + every { realm.instance.createObject(PollResponseAggregatedSummaryEntity::class.java) } returns PollResponseAggregatedSummaryEntity() + val powerLevelsHelper = mockRedactionPowerLevels("another-sender-id", false) + val event = A_POLL_END_EVENT.copy(senderId = "another-sender-id") + pollAggregationProcessor.handlePollEndEvent(session, powerLevelsHelper, realm.instance, event).shouldBeFalse() + } + + private inline fun <reified T : RealmModel> RealmQuery<T>.givenEqualTo(fieldName: String, value: String, result: RealmQuery<T>) { + every { equalTo(fieldName, value) } returns result + } + + private fun mockEventAnnotationsSummaryEntity() { + val queryResult = realm.givenWhereReturns(result = EventAnnotationsSummaryEntity()) + queryResult.givenEqualTo(EventAnnotationsSummaryEntityFields.ROOM_ID, A_POLL_REPLACE_EVENT.roomId!!, queryResult) + queryResult.givenEqualTo(EventAnnotationsSummaryEntityFields.EVENT_ID, A_POLL_REPLACE_EVENT.eventId!!, queryResult) + } + + private fun mockRoom( + roomId: String, + eventId: String + ) { + val room = mockk<Room>() + every { session.getRoom(roomId) } returns room + every { room.getTimelineEvent(eventId) } returns A_TIMELINE_EVENT + } + + private fun mockRedactionPowerLevels(userId: String, isAbleToRedact: Boolean): PowerLevelsHelper { + val powerLevelsHelper = mockk<PowerLevelsHelper>() + every { powerLevelsHelper.isUserAbleToRedact(userId) } returns isAbleToRedact + return powerLevelsHelper + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollEventsTestData.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollEventsTestData.kt new file mode 100644 index 0000000000000000000000000000000000000000..129d49633e2f9135500052efdba4093e0394236f --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/aggregation/poll/PollEventsTestData.kt @@ -0,0 +1,171 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.aggregation.poll + +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.events.model.RelationType +import org.matrix.android.sdk.api.session.events.model.toContent +import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent +import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent +import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent +import org.matrix.android.sdk.api.session.room.model.message.PollAnswer +import org.matrix.android.sdk.api.session.room.model.message.PollCreationInfo +import org.matrix.android.sdk.api.session.room.model.message.PollQuestion +import org.matrix.android.sdk.api.session.room.model.message.PollResponse +import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent +import org.matrix.android.sdk.api.session.room.sender.SenderInfo +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent + +object PollEventsTestData { + internal const val A_USER_ID_1 = "@user_1:matrix.org" + internal const val A_ROOM_ID = "!sUeOGZKsBValPTUMax:matrix.org" + internal const val AN_EVENT_ID = "\$vApgexcL8Vfh-WxYKsFKCDooo67ttbjm3TiVKXaWijU" + + internal val A_POLL_CONTENT = MessagePollContent( + unstablePollCreationInfo = PollCreationInfo( + question = PollQuestion( + unstableQuestion = "What is your favourite coffee?" + ), + maxSelections = 1, + answers = listOf( + PollAnswer( + id = "5ef5f7b0-c9a1-49cf-a0b3-374729a43e76", + unstableAnswer = "Double Espresso" + ), + PollAnswer( + id = "ec1a4db0-46d8-4d7a-9bb6-d80724715938", + unstableAnswer = "Macchiato" + ), + PollAnswer( + id = "3677ca8e-061b-40ab-bffe-b22e4e88fcad", + unstableAnswer = "Iced Coffee" + ) + ) + ) + ) + + internal val A_POLL_RESPONSE_CONTENT = MessagePollResponseContent( + unstableResponse = PollResponse( + answers = listOf("5ef5f7b0-c9a1-49cf-a0b3-374729a43e76") + ), + relatesTo = RelationDefaultContent( + type = RelationType.REFERENCE, + eventId = AN_EVENT_ID + ) + ) + + internal val A_POLL_END_CONTENT = MessageEndPollContent( + relatesTo = RelationDefaultContent( + type = RelationType.REFERENCE, + eventId = AN_EVENT_ID + ) + ) + + internal val AN_INVALID_POLL_RESPONSE_CONTENT = MessagePollResponseContent( + unstableResponse = PollResponse( + answers = listOf("fake-option-id") + ), + relatesTo = RelationDefaultContent( + type = RelationType.REFERENCE, + eventId = AN_EVENT_ID + ) + ) + + internal val A_POLL_START_EVENT = Event( + type = EventType.POLL_START.first(), + eventId = AN_EVENT_ID, + originServerTs = 1652435922563, + senderId = A_USER_ID_1, + roomId = A_ROOM_ID, + content = A_POLL_CONTENT.toContent() + ) + + internal val A_POLL_RESPONSE_EVENT = Event( + type = EventType.POLL_RESPONSE.first(), + eventId = AN_EVENT_ID, + originServerTs = 1652435922563, + senderId = A_USER_ID_1, + roomId = A_ROOM_ID, + content = A_POLL_RESPONSE_CONTENT.toContent() + ) + + internal val A_POLL_END_EVENT = Event( + type = EventType.POLL_END.first(), + eventId = AN_EVENT_ID, + originServerTs = 1652435922563, + senderId = A_USER_ID_1, + roomId = A_ROOM_ID, + content = A_POLL_END_CONTENT.toContent() + ) + + internal val A_TIMELINE_EVENT = TimelineEvent( + root = A_POLL_START_EVENT, + localId = 1234, + eventId = AN_EVENT_ID, + displayIndex = 0, + senderInfo = SenderInfo(A_USER_ID_1, "A_USER_ID_1", true, null) + ) + + internal val A_POLL_RESPONSE_EVENT_WITH_A_WRONG_REFERENCE = A_POLL_RESPONSE_EVENT.copy( + content = A_POLL_RESPONSE_CONTENT + .copy( + relatesTo = RelationDefaultContent( + type = RelationType.REPLACE, + eventId = null + ) + ) + .toContent() + ) + + internal val A_POLL_REPLACE_EVENT = A_POLL_START_EVENT.copy( + content = A_POLL_CONTENT + .copy( + relatesTo = RelationDefaultContent( + type = RelationType.REPLACE, + eventId = AN_EVENT_ID + ) + ) + .toContent() + ) + + internal val A_BROKEN_POLL_REPLACE_EVENT = A_POLL_START_EVENT.copy( + content = A_POLL_CONTENT + .copy( + relatesTo = RelationDefaultContent( + type = RelationType.REPLACE, + eventId = null + ) + ) + .toContent() + ) + + internal val A_POLL_REFERENCE_EVENT = A_POLL_START_EVENT.copy( + content = A_POLL_CONTENT + .copy( + relatesTo = RelationDefaultContent( + type = RelationType.REFERENCE, + eventId = AN_EVENT_ID + ) + ) + .toContent() + ) + + internal val AN_INVALID_POLL_RESPONSE_EVENT = A_POLL_RESPONSE_EVENT.copy( + content = AN_INVALID_POLL_RESPONSE_CONTENT.toContent() + ) +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRealm.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRealm.kt new file mode 100644 index 0000000000000000000000000000000000000000..c07f8e187363e934a79ca52e16ae224f1ecff85f --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRealm.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.test.fakes + +import io.mockk.every +import io.mockk.mockk +import io.realm.Realm +import io.realm.RealmModel +import io.realm.RealmQuery +import io.realm.kotlin.where + +internal class FakeRealm { + + val instance = mockk<Realm>(relaxed = true) + + inline fun <reified T : RealmModel> givenWhereReturns(result: T?): RealmQuery<T> { + val queryResult = mockk<RealmQuery<T>>() + every { queryResult.findFirst() } returns result + every { instance.where<T>() } returns queryResult + return queryResult + } +} diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRequestExecutor.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRequestExecutor.kt index 2f332a89a807be3d15d43842ac9e34b8a848fadb..ad20abf63c285763222fdd0c2a8cda7b64fe8fb1 100644 --- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRequestExecutor.kt +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeRequestExecutor.kt @@ -21,11 +21,13 @@ import org.matrix.android.sdk.internal.network.RequestExecutor internal class FakeRequestExecutor : RequestExecutor { - override suspend fun <DATA> executeRequest(globalErrorReceiver: GlobalErrorReceiver?, - canRetry: Boolean, - maxDelayBeforeRetry: Long, - maxRetriesCount: Int, - requestBlock: suspend () -> DATA): DATA { + override suspend fun <DATA> executeRequest( + globalErrorReceiver: GlobalErrorReceiver?, + canRetry: Boolean, + maxDelayBeforeRetry: Long, + maxRetriesCount: Int, + requestBlock: suspend () -> DATA + ): DATA { return requestBlock() } }